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 - name: Exec OpenIM API test
run: | run: |
sudo make test-api
mkdir -p ./tmp mkdir -p ./tmp
touch ./tmp/test.md touch ./tmp/test.md
echo "# OpenIM Test" >> ./tmp/test.md echo "# OpenIM Test" >> ./tmp/test.md
@ -104,6 +105,7 @@ jobs:
- name: Exec OpenIM E2E Test - name: Exec OpenIM E2E Test
run: | run: |
sudo make test-e2e
echo "" >> ./tmp/test.md echo "" >> ./tmp/test.md
echo "## OpenIM E2E Test" >> ./tmp/test.md echo "## OpenIM E2E Test" >> ./tmp/test.md
echo "<details><summary>Command Output for OpenIM E2E Test</summary>" >> ./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 echo $latest_tag > pkg/common/config/version
continue-on-error: true 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 - name: Run unit test and get test coverage
run: | run: |
make cover make cover

@ -40,10 +40,14 @@ run:
# "/" will be replaced by current OS file path separator to properly work # "/" will be replaced by current OS file path separator to properly work
# on Windows. # on Windows.
skip-dirs: skip-dirs:
- components
- docs
- util - util
- .*~ - .*~
- api/swagger/docs - api/swagger/docs
- server/docs - server/docs
- components/mnt/config/certs
- logs
# default is true. Enables skipping of directories: # default is true. Enables skipping of directories:
# vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
@ -58,6 +62,12 @@ run:
skip-files: skip-files:
- ".*\\.my\\.go$" - ".*\\.my\\.go$"
- _test.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": # 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 # If invoked with -mod=readonly, the go command is disallowed from the implicit
@ -108,7 +118,6 @@ linters-settings:
right-to-left-isolate: true right-to-left-isolate: true
first-strong-isolate: true first-strong-isolate: true
pop-directional-isolate: true pop-directional-isolate: true
dogsled:
# checks assignments with too many blank identifiers; default is 2 # checks assignments with too many blank identifiers; default is 2
max-blank-identifiers: 2 max-blank-identifiers: 2
dupl: dupl:
@ -131,7 +140,7 @@ linters-settings:
# path to a file containing a list of functions to exclude from checking # path to a file containing a list of functions to exclude from checking
# see https://github.com/kisielk/errcheck#excluding-functions for details # see https://github.com/kisielk/errcheck#excluding-functions for details
#exclude: errcheck.txt # exclude: errcheck.txt
errorlint: errorlint:
# Check whether fmt.Errorf uses the %w verb for formatting errors. See the readme for caveats # Check whether fmt.Errorf uses the %w verb for formatting errors. See the readme for caveats
@ -418,7 +427,7 @@ linters-settings:
govet: govet:
# report about shadowed variables # report about shadowed variables
check-shadowing: true check-shadowing: false
# settings per analyzer # settings per analyzer
settings: settings:
@ -489,9 +498,9 @@ linters-settings:
- github.com\/user\/package\/v4\.Type - github.com\/user\/package\/v4\.Type
lll: 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 # '\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 in spaces. Default to 1.
tab-width: 4 tab-width: 4
maligned: maligned:
@ -715,17 +724,33 @@ linters:
# enable-all: true # enable-all: true
disable-all: true disable-all: true
enable: enable:
- typecheck # 基本的类型检查 - typecheck # Basic type checking
- gofmt # 格式检查 - gofmt # Format check
- govet # Go 语言的标准检查工具 - govet # Go's standard linting tool
- gosimple # 简化代码的建议 - gosimple # Suggestions for simplifying code
- misspell # 拼写错误 - errcheck
- staticcheck # 静态检查 - decorder
- unused # 未使用的代码检查 - ineffassign
- goimports # 检查导入是否正确排序和格式化 - revive
- godot # 注释句点检查 - reassign
- bodyclose # 确保 HTTP response body 被关闭 - tparallel
- errcheck # 检查是否遗漏了错误返回值 - 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 fast: true
issues: issues:
@ -792,6 +817,11 @@ issues:
- lll - lll
source: "^//go:generate " source: "^//go:generate "
- text: ".*[\u4e00-\u9fa5]+.*"
linters:
- golint
source: "^//.*$"
# Independently from option `exclude` we use default exclude patterns, # Independently from option `exclude` we use default exclude patterns,
# it can be disabled by this option. To list all # it can be disabled by this option. To list all
# excluded by default patterns execute `golangci-lint run --help`. # excluded by default patterns execute `golangci-lint run --help`.

@ -8,6 +8,12 @@
## [Unreleased] ## [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> <a name="v3.5.1-alpha.1"></a>
## [v3.5.1-alpha.1] - 2024-01-09 ## [v3.5.1-alpha.1] - 2024-01-09
@ -59,7 +65,9 @@
- Merge branch 'tuoyun' - 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.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.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 [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: imports:
@$(MAKE) go.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 .PHONY: clean
clean: clean:
@$(MAKE) go.clean @$(MAKE) go.clean

@ -51,6 +51,15 @@
</p> </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 ## Ⓜ️ 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. 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 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). 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). 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) - [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) - [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 ## :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. 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 package main
import ( import (
"context"
"fmt"
"net"
"net/http"
_ "net/http/pprof" _ "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/cmd"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
"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"
) )
func main() { func main() {
apiCmd := cmd.NewApiCmd() apiCmd := cmd.NewApiCmd()
apiCmd.AddPortFlag() apiCmd.AddPortFlag()
apiCmd.AddPrometheusPortFlag() apiCmd.AddPrometheusPortFlag()
apiCmd.AddApi(run)
if err := apiCmd.Execute(); err != nil { if err := apiCmd.Execute(); err != nil {
util.ExitWithError(err) 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 package main
import ( import (
"github.com/openimsdk/open-im-server/v3/internal/tools"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
) )
func main() { func main() {
cronTaskCmd := cmd.NewCronTaskCmd() cronTaskCmd := cmd.NewCronTaskCmd()
if err := cronTaskCmd.Exec(tools.StartTask); err != nil { if err := cronTaskCmd.Exec(); err != nil {
util.ExitWithError(err) util.ExitWithError(err)
} }
} }

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

@ -17,18 +17,14 @@ package main
import ( import (
"github.com/openimsdk/open-im-server/v3/internal/push" "github.com/openimsdk/open-im-server/v3/internal/push"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
) )
func main() { func main() {
pushCmd := cmd.NewRpcCmd(cmd.RpcPushServer) pushCmd := cmd.NewRpcCmd(cmd.RpcPushServer, push.Start)
pushCmd.AddPortFlag() pushCmd.AddPortFlag()
pushCmd.AddPrometheusPortFlag() pushCmd.AddPrometheusPortFlag()
if err := pushCmd.Exec(); err != nil { if err := pushCmd.Exec(); err != nil {
panic(err.Error())
}
if err := pushCmd.StartSvr(config.Config.RpcRegisterName.OpenImPushName, push.Start); err != nil {
util.ExitWithError(err) util.ExitWithError(err)
} }
} }

@ -17,19 +17,14 @@ package main
import ( import (
"github.com/openimsdk/open-im-server/v3/internal/rpc/auth" "github.com/openimsdk/open-im-server/v3/internal/rpc/auth"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
) )
func main() { func main() {
authCmd := cmd.NewRpcCmd(cmd.RpcAuthServer) authCmd := cmd.NewRpcCmd(cmd.RpcAuthServer, auth.Start)
authCmd.AddPortFlag() authCmd.AddPortFlag()
authCmd.AddPrometheusPortFlag() authCmd.AddPrometheusPortFlag()
if err := authCmd.Exec(); err != nil { if err := authCmd.Exec(); err != nil {
panic(err.Error())
}
if err := authCmd.StartSvr(config.Config.RpcRegisterName.OpenImAuthName, auth.Start); err != nil {
util.ExitWithError(err) util.ExitWithError(err)
} }
} }

@ -17,18 +17,14 @@ package main
import ( import (
"github.com/openimsdk/open-im-server/v3/internal/rpc/conversation" "github.com/openimsdk/open-im-server/v3/internal/rpc/conversation"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
) )
func main() { func main() {
rpcCmd := cmd.NewRpcCmd(cmd.RpcConversationServer) rpcCmd := cmd.NewRpcCmd(cmd.RpcConversationServer, conversation.Start)
rpcCmd.AddPortFlag() rpcCmd.AddPortFlag()
rpcCmd.AddPrometheusPortFlag() rpcCmd.AddPrometheusPortFlag()
if err := rpcCmd.Exec(); err != nil { if err := rpcCmd.Exec(); err != nil {
panic(err.Error())
}
if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImConversationName, conversation.Start); err != nil {
util.ExitWithError(err) util.ExitWithError(err)
} }
} }

@ -17,18 +17,14 @@ package main
import ( import (
"github.com/openimsdk/open-im-server/v3/internal/rpc/friend" "github.com/openimsdk/open-im-server/v3/internal/rpc/friend"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
) )
func main() { func main() {
rpcCmd := cmd.NewRpcCmd(cmd.RpcFriendServer) rpcCmd := cmd.NewRpcCmd(cmd.RpcFriendServer, friend.Start)
rpcCmd.AddPortFlag() rpcCmd.AddPortFlag()
rpcCmd.AddPrometheusPortFlag() rpcCmd.AddPrometheusPortFlag()
if err := rpcCmd.Exec(); err != nil { if err := rpcCmd.Exec(); err != nil {
panic(err.Error())
}
if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImFriendName, friend.Start); err != nil {
util.ExitWithError(err) util.ExitWithError(err)
} }
} }

@ -17,18 +17,14 @@ package main
import ( import (
"github.com/openimsdk/open-im-server/v3/internal/rpc/group" "github.com/openimsdk/open-im-server/v3/internal/rpc/group"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
) )
func main() { func main() {
rpcCmd := cmd.NewRpcCmd(cmd.RpcGroupServer) rpcCmd := cmd.NewRpcCmd(cmd.RpcGroupServer, group.Start)
rpcCmd.AddPortFlag() rpcCmd.AddPortFlag()
rpcCmd.AddPrometheusPortFlag() rpcCmd.AddPrometheusPortFlag()
if err := rpcCmd.Exec(); err != nil { if err := rpcCmd.Exec(); err != nil {
panic(err.Error())
}
if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImGroupName, group.Start); err != nil {
util.ExitWithError(err) util.ExitWithError(err)
} }
} }

@ -17,18 +17,14 @@ package main
import ( import (
"github.com/openimsdk/open-im-server/v3/internal/rpc/msg" "github.com/openimsdk/open-im-server/v3/internal/rpc/msg"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
) )
func main() { func main() {
rpcCmd := cmd.NewRpcCmd(cmd.RpcMsgServer) rpcCmd := cmd.NewRpcCmd(cmd.RpcMsgServer, msg.Start)
rpcCmd.AddPortFlag() rpcCmd.AddPortFlag()
rpcCmd.AddPrometheusPortFlag() rpcCmd.AddPrometheusPortFlag()
if err := rpcCmd.Exec(); err != nil { if err := rpcCmd.Exec(); err != nil {
panic(err.Error())
}
if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImMsgName, msg.Start); err != nil {
util.ExitWithError(err) util.ExitWithError(err)
} }
} }

@ -17,18 +17,14 @@ package main
import ( import (
"github.com/openimsdk/open-im-server/v3/internal/rpc/third" "github.com/openimsdk/open-im-server/v3/internal/rpc/third"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
) )
func main() { func main() {
rpcCmd := cmd.NewRpcCmd(cmd.RpcThirdServer) rpcCmd := cmd.NewRpcCmd(cmd.RpcThirdServer, third.Start)
rpcCmd.AddPortFlag() rpcCmd.AddPortFlag()
rpcCmd.AddPrometheusPortFlag() rpcCmd.AddPrometheusPortFlag()
if err := rpcCmd.Exec(); err != nil { if err := rpcCmd.Exec(); err != nil {
panic(err.Error())
}
if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImThirdName, third.Start); err != nil {
util.ExitWithError(err) util.ExitWithError(err)
} }
} }

@ -17,18 +17,14 @@ package main
import ( import (
"github.com/openimsdk/open-im-server/v3/internal/rpc/user" "github.com/openimsdk/open-im-server/v3/internal/rpc/user"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd" "github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil" util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
) )
func main() { func main() {
rpcCmd := cmd.NewRpcCmd(cmd.RpcUserServer) rpcCmd := cmd.NewRpcCmd(cmd.RpcUserServer, user.Start)
rpcCmd.AddPortFlag() rpcCmd.AddPortFlag()
rpcCmd.AddPrometheusPortFlag() rpcCmd.AddPrometheusPortFlag()
if err := rpcCmd.Exec(); err != nil { if err := rpcCmd.Exec(); err != nil {
panic(err.Error())
}
if err := rpcCmd.StartSvr(config.Config.RpcRegisterName.OpenImUserName, user.Start); err != nil {
util.ExitWithError(err) util.ExitWithError(err)
} }
} }

@ -153,6 +153,13 @@ object:
accessKeySecret: '' accessKeySecret: ''
sessionToken: '' sessionToken: ''
publicRead: false publicRead: false
aws:
endpoint: ""
region: ""
bucket: "demo-9999999"
accessKeyID: ''
accessKeySecret: ''
publicRead: false
###################### RPC Port Configuration ###################### ###################### RPC Port Configuration ######################
# RPC service ports # RPC service ports

@ -53,7 +53,7 @@
}, },
"id": 16, "id": 16,
"panels": [], "panels": [],
"title": "openim自定义指标", "title": "openim Custom Metrics",
"type": "row" "type": "row"
}, },
{ {
@ -144,7 +144,7 @@
"refId": "A" "refId": "A"
} }
], ],
"title": "在线人数", "title": "Online population",
"type": "timeseries" "type": "timeseries"
}, },
{ {
@ -235,7 +235,7 @@
"refId": "A" "refId": "A"
} }
], ],
"title": "登入/注册人数", "title": "Login/registration numbers",
"type": "timeseries" "type": "timeseries"
}, },
{ {
@ -1345,7 +1345,7 @@
"type": "timeseries" "type": "timeseries"
} }
], ],
"title": "应用服务器流量指标", "title": "Traffic indicators of the application server",
"type": "row" "type": "row"
} }
], ],

@ -153,6 +153,13 @@ object:
accessKeySecret: ${KODO_ACCESS_KEY_SECRET} accessKeySecret: ${KODO_ACCESS_KEY_SECRET}
sessionToken: ${KODO_SESSION_TOKEN} sessionToken: ${KODO_SESSION_TOKEN}
publicRead: ${KODO_PUBLIC_READ} 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 Port Configuration ######################
# RPC service ports # RPC service ports

@ -3,7 +3,15 @@
- [Code conventions](#code-conventions) - [Code conventions](#code-conventions)
- [POSIX shell](#posix-shell) - [POSIX shell](#posix-shell)
- [Go](#go) - [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) - [Testing conventions](#testing-conventions)
## POSIX shell ## 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. + 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`. + 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 ## Testing conventions

@ -449,7 +449,7 @@ This section involves configuring the log settings, including storage location,
| Parameter | Example Value | Description | | 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_ROTATION_TIME | "24" | Log rotation time (in hours) |
| LOG_REMAIN_ROTATION_COUNT | "2" | Number of log rotations to retain | | LOG_REMAIN_ROTATION_COUNT | "2" | Number of log rotations to retain |
| LOG_REMAIN_LOG_LEVEL | "6" | Log level to retain | | LOG_REMAIN_LOG_LEVEL | "6" | Log level to retain |

@ -26,19 +26,19 @@ jwt "github.com/dgrijalva/jwt-go/v4"
```go ```go
import ( import (
// go standard package // go standard package
"fmt" "fmt"
// third party package // third party package
"github.com/jinzhu/gorm" "github.com/jinzhu/gorm"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
// Anonymous packages are grouped separately, and anonymous package references are explained // Anonymous packages are grouped separately, and anonymous package references are explained
// import mysql driver // import mysql driver
_ "github.com/jinzhu/gorm/dialects/mysql" _ "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 ```go
var ( var (
Width int Width int
Height int Height int
) )
``` ```
- When initializing a structure reference, please use `&T{}` instead of `new(T)` to make it consistent with structure initialization. - When initializing a structure reference, please use `&T{}` instead of `new(T)` to make it consistent with structure initialization.
```go ```go
// bad // bad
sptr := new(T) sptr := new(T)
sptr.Name = "bar" sptr.Name = "bar"
// good // good
sptr := &T{Name: "bar"} sptr := &T{Name: "bar"}
``` ```
- The struct declaration and initialization format takes multiple lines and is defined as follows. - The struct declaration and initialization format takes multiple lines and is defined as follows.
```go ```go
type User struct{ type User struct{
Username string Username string
Email string Email string
} }
user := User{ user := User{
Username: "belm", Username: "belm",
Email: "nosbelm@qq.com", Email: "nosbelm@qq.com",
} }
``` ```
@ -217,20 +217,20 @@ if err != nil {
// bad // bad
v, err := foo() v, err := foo()
if err != nil || v == nil { if err != nil || v == nil {
// error handling // error handling
return err return err
} }
//good //good
v, err := foo() v, err := foo()
if err != nil { if err != nil {
// error handling // error handling
return err return err
} }
if v == nil { if v == nil {
// error handling // error handling
return errors. New("invalid value v") return errors. New("invalid value v")
} }
``` ```
@ -239,13 +239,14 @@ return errors. New("invalid value v")
```go ```go
v, err := f() v, err := f()
if err != nil { if err != nil {
// error handling // error handling
return // or continue. return // or continue.
} }
``` ```
- Bug description suggestions - Bug description suggestions
- Error descriptions start with a lowercase letter and do not end with punctuation, for example: - Error descriptions start with a lowercase letter and do not end with punctuation, for example:
```go ```go
// bad // bad
errors.New("Redis connection failed") errors.New("Redis connection failed")
@ -254,6 +255,7 @@ errors.New("redis connection failed.")
// good // good
errors.New("redis connection failed") errors.New("redis connection failed")
``` ```
- Tell users what they can do, not what they can't. - 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 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`. - When declaring that a format is incorrect, use must not. For example, `must not contain`.
@ -359,18 +361,18 @@ u := User{
For example: For example:
``` ```go
// Seeking to an offset before the start of the file is an error. // 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 // Seeking to any positive offset is legal, but the behavior of subsequent
// I/O operations on the underlying object are implementation-dependent. // I/O operations on the underlying object are implementation-dependent.
type Seeker interface { 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. // ReadWriter is the interface that groups the basic Read and Write methods.
type ReadWriter interface { type ReadWriter interface {
reader reader
Writer Writer
} }
``` ```
@ -386,7 +388,7 @@ Writer
Some common nouns are listed below. Some common nouns are listed below.
``` ```go
// A GonicMapper that contains a list of common initialisms taken from golang/lint // A GonicMapper that contains a list of common initialisms taken from golang/lint
var LintGonicMapper = GonicMapper{ var LintGonicMapper = GonicMapper{
"API": true, "API": true,
@ -523,6 +525,7 @@ package genericclioptions
// ErrSigningMethod defines invalid signing method error. // ErrSigningMethod defines invalid signing method error.
var ErrSigningMethod = errors. New("Invalid signing method") 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: - 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 ```go
// Code must start with 1xxxxx. // 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. // BeforeUpdate run before update database record.
func (p *Policy) BeforeUpdate() (err error) { func (p *Policy) BeforeUpdate() (err error) {
// normal code // normal code
return nil return nil
} }
``` ```
@ -743,9 +746,9 @@ for i := 0; i < 10; i++ {
```go ```go
// bad // bad
for file := range files { for file := range files {
fd, err := os. Open(file) fd, err := os. Open(file)
if err != nil { if err != nil {
return err return err
} }
defer fd. Close() defer fd. Close()
// normal code // normal code
@ -753,14 +756,14 @@ defer fd. Close()
//good //good
for file := range files { for file := range files {
func() { func() {
fd, err := os. Open(file) fd, err := os. Open(file)
if err != nil { if err != nil {
return err return err
} }
defer fd. Close() defer fd. Close()
// normal code // normal code
}() }()
} }
``` ```
@ -888,6 +891,7 @@ type LogHandler struct {
} }
var_http.Handler = LogHandler{} 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. - 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 ### 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. - 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. - 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. - 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 ( require (
firebase.google.com/go v3.13.0+incompatible firebase.google.com/go v3.13.0+incompatible
github.com/OpenIMSDK/protocol v0.0.55 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/bwmarrin/snowflake v0.3.0 // indirect
github.com/dtm-labs/rockscache v0.1.1 github.com/dtm-labs/rockscache v0.1.1
github.com/gin-gonic/gin v1.9.1 github.com/gin-gonic/gin v1.9.1

@ -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/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 h1:eBjg8DyuhxGmuCUjpoZjg6MJJJXU/xJ3xJwFhrn34yA=
github.com/OpenIMSDK/protocol v0.0.55/go.mod h1:F25dFrwrIx3lkNoiuf6FkCfxuwf8L4Z8UIsdTHP/r0Y= 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.37 h1:qvDqmA4RbEJtPjZouWCkVuf/pjm6Y8nUrG5iH2gcnOg=
github.com/OpenIMSDK/tools v0.0.35/go.mod h1:wBfR5CYmEyvxl03QJbTkhz1CluK6J4/lX0lviu8JAjE= 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/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=

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

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

@ -15,11 +15,9 @@
package api package api
import ( import (
"github.com/gin-gonic/gin"
"github.com/OpenIMSDK/protocol/auth" "github.com/OpenIMSDK/protocol/auth"
"github.com/OpenIMSDK/tools/a2r" "github.com/OpenIMSDK/tools/a2r"
"github.com/gin-gonic/gin"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
) )

@ -15,11 +15,9 @@
package api package api
import ( import (
"github.com/gin-gonic/gin"
"github.com/OpenIMSDK/protocol/conversation" "github.com/OpenIMSDK/protocol/conversation"
"github.com/OpenIMSDK/tools/a2r" "github.com/OpenIMSDK/tools/a2r"
"github.com/gin-gonic/gin"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
) )

@ -15,24 +15,20 @@
package api package api
import ( import (
"github.com/go-playground/validator/v10"
"github.com/OpenIMSDK/protocol/constant" "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 { func RequiredIf(fl validator.FieldLevel) bool {
sessionType := fl.Parent().FieldByName("SessionType").Int() sessionType := fl.Parent().FieldByName("SessionType").Int()
switch sessionType { switch sessionType {
case constant.SingleChatType, constant.NotificationChatType: case constant.SingleChatType, constant.NotificationChatType:
if fl.FieldName() == "RecvID" { return fl.FieldName() != "RecvID" || fl.Field().String() != ""
return fl.Field().String() != ""
}
case constant.GroupChatType, constant.SuperGroupChatType: case constant.GroupChatType, constant.SuperGroupChatType:
if fl.FieldName() == "GroupID" { return fl.FieldName() != "GroupID" || fl.Field().String() != ""
return fl.Field().String() != ""
}
default: default:
return true return true
} }
return true
} }

@ -17,10 +17,8 @@ package api
import ( import (
"github.com/OpenIMSDK/protocol/friend" "github.com/OpenIMSDK/protocol/friend"
"github.com/OpenIMSDK/tools/a2r" "github.com/OpenIMSDK/tools/a2r"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
) )
type FriendApi rpcclient.Friend type FriendApi rpcclient.Friend

@ -17,10 +17,8 @@ package api
import ( import (
"github.com/OpenIMSDK/protocol/group" "github.com/OpenIMSDK/protocol/group"
"github.com/OpenIMSDK/tools/a2r" "github.com/OpenIMSDK/tools/a2r"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
) )
type GroupApi rpcclient.Group type GroupApi rpcclient.Group

@ -27,11 +27,9 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10" "github.com/go-playground/validator/v10"
"github.com/mitchellh/mapstructure" "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/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/apistruct"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "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. // 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. // 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")) apiresp.GinError(c, errs.ErrNoPermission.Wrap("only app manager can send message"))
return return
@ -210,7 +208,6 @@ func (m *MessageApi) SendMessage(c *gin.Context) {
sendMsgReq, err := m.getSendMsgReq(c, req.SendMsg) sendMsgReq, err := m.getSendMsgReq(c, req.SendMsg)
if err != nil { if err != nil {
// Log and respond with an error if preparation fails. // Log and respond with an error if preparation fails.
log.ZError(c, "decodeData failed", err)
apiresp.GinError(c, err) apiresp.GinError(c, err)
return return
} }
@ -226,7 +223,6 @@ func (m *MessageApi) SendMessage(c *gin.Context) {
if err != nil { if err != nil {
// Set the status to failed and respond with an error if sending fails. // Set the status to failed and respond with an error if sending fails.
status = constant.MsgSendFailed status = constant.MsgSendFailed
log.ZError(c, "send message err", err)
apiresp.GinError(c, err) apiresp.GinError(c, err)
return return
} }
@ -240,7 +236,8 @@ func (m *MessageApi) SendMessage(c *gin.Context) {
}) })
if err != nil { if err != nil {
// Log the error if updating the status fails. // 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. // Respond with a success message and the response payload.
@ -259,7 +256,7 @@ func (m *MessageApi) SendBusinessNotification(c *gin.Context) {
return return
} }
if !authverify.IsAppManagerUid(c) { if !authverify.IsAppManagerUid(c, m.Config) {
apiresp.GinError(c, errs.ErrNoPermission.Wrap("only app manager can send message")) apiresp.GinError(c, errs.ErrNoPermission.Wrap("only app manager can send message"))
return return
} }
@ -299,25 +296,22 @@ func (m *MessageApi) BatchSendMsg(c *gin.Context) {
resp apistruct.BatchSendMsgResp resp apistruct.BatchSendMsgResp
) )
if err := c.BindJSON(&req); err != nil { if err := c.BindJSON(&req); err != nil {
log.ZError(c, "BatchSendMsg BindJSON failed", err)
apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap())
return return
} }
log.ZInfo(c, "BatchSendMsg", "req", req) 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")) apiresp.GinError(c, errs.ErrNoPermission.Wrap("only app manager can send message"))
return return
} }
var recvIDs []string var recvIDs []string
var err error
if req.IsSendAll { if req.IsSendAll {
pageNumber := 1 pageNumber := 1
showNumber := 500 showNumber := 500
for { for {
recvIDsPart, err := m.userRpcClient.GetAllUserIDs(c, int32(pageNumber), int32(showNumber)) recvIDsPart, err := m.userRpcClient.GetAllUserIDs(c, int32(pageNumber), int32(showNumber))
if err != nil { if err != nil {
log.ZError(c, "GetAllUserIDs failed", err)
apiresp.GinError(c, err) apiresp.GinError(c, err)
return return
} }
@ -333,7 +327,6 @@ func (m *MessageApi) BatchSendMsg(c *gin.Context) {
log.ZDebug(c, "BatchSendMsg nums", "nums ", len(recvIDs)) log.ZDebug(c, "BatchSendMsg nums", "nums ", len(recvIDs))
sendMsgReq, err := m.getSendMsgReq(c, req.SendMsg) sendMsgReq, err := m.getSendMsgReq(c, req.SendMsg)
if err != nil { if err != nil {
log.ZError(c, "decodeData failed", err)
apiresp.GinError(c, err) apiresp.GinError(c, err)
return return
} }

@ -17,53 +17,138 @@ package api
import ( import (
"context" "context"
"fmt" "fmt"
"net"
"net/http" "net/http"
"os"
"os/signal"
"strconv"
"syscall"
"time"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/apiresp" "github.com/OpenIMSDK/tools/apiresp"
"github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mw"
"github.com/OpenIMSDK/tools/tokenverify" "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"
"github.com/gin-gonic/gin/binding" "github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10" "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" "github.com/redis/go-redis/v9"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/credentials/insecure"
)
"github.com/OpenIMSDK/tools/discoveryregistry" func Start(config *config.GlobalConfig, port int, proPort int) error {
"github.com/OpenIMSDK/tools/log" log.ZDebug(context.Background(), "configAPI1111111111111111111", config, "port", port, "javafdasfs")
"github.com/OpenIMSDK/tools/mw" 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" var client discoveryregistry.SvcDiscoveryRegistry
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
)
func NewGinRouter(discov discoveryregistry.SvcDiscoveryRegistry, rdb redis.UniversalClient) *gin.Engine { // Determine whether zk is passed according to whether it is a clustered deployment
discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) // 默认RPC中间件 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) gin.SetMode(gin.ReleaseMode)
r := gin.New() r := gin.New()
if v, ok := binding.Validator.Engine().(*validator.Validate); ok { if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
_ = v.RegisterValidation("required_if", RequiredIf) _ = v.RegisterValidation("required_if", RequiredIf)
} }
log.ZInfo(context.Background(), "load config", "config", config.Config)
r.Use(gin.Recovery(), mw.CorsHandler(), mw.GinParseOperationID()) r.Use(gin.Recovery(), mw.CorsHandler(), mw.GinParseOperationID())
// init rpc client here // init rpc client here
userRpc := rpcclient.NewUser(discov) userRpc := rpcclient.NewUser(disCov, config)
groupRpc := rpcclient.NewGroup(discov) groupRpc := rpcclient.NewGroup(disCov, config)
friendRpc := rpcclient.NewFriend(discov) friendRpc := rpcclient.NewFriend(disCov, config)
messageRpc := rpcclient.NewMessage(discov) messageRpc := rpcclient.NewMessage(disCov, config)
conversationRpc := rpcclient.NewConversation(discov) conversationRpc := rpcclient.NewConversation(disCov, config)
authRpc := rpcclient.NewAuth(discov) authRpc := rpcclient.NewAuth(disCov, config)
thirdRpc := rpcclient.NewThird(discov) thirdRpc := rpcclient.NewThird(disCov, config)
u := NewUserApi(*userRpc) u := NewUserApi(*userRpc)
m := NewMessageApi(messageRpc, userRpc) m := NewMessageApi(messageRpc, userRpc)
ParseToken := GinParseToken(rdb) ParseToken := GinParseToken(rdb, config)
userRouterGroup := r.Group("/user") userRouterGroup := r.Group("/user")
{ {
userRouterGroup.POST("/user_register", u.UserRegister) userRouterGroup.POST("/user_register", u.UserRegister)
@ -157,8 +242,8 @@ func NewGinRouter(discov discoveryregistry.SvcDiscoveryRegistry, rdb redis.Unive
// Third service // Third service
thirdGroup := r.Group("/third", ParseToken) thirdGroup := r.Group("/third", ParseToken)
{ {
thirdGroup.GET("/prometheus", GetPrometheus)
t := NewThirdApi(*thirdRpc) t := NewThirdApi(*thirdRpc)
thirdGroup.GET("/prometheus", t.GetPrometheus)
thirdGroup.POST("/fcm_update_token", t.FcmUpdateToken) thirdGroup.POST("/fcm_update_token", t.FcmUpdateToken)
thirdGroup.POST("/set_app_badge", t.SetAppBadge) thirdGroup.POST("/set_app_badge", t.SetAppBadge)
@ -225,11 +310,12 @@ func NewGinRouter(discov discoveryregistry.SvcDiscoveryRegistry, rdb redis.Unive
return r return r
} }
func GinParseToken(rdb redis.UniversalClient) gin.HandlerFunc { func GinParseToken(rdb redis.UniversalClient, config *config.GlobalConfig) gin.HandlerFunc {
dataBase := controller.NewAuthDatabase( dataBase := controller.NewAuthDatabase(
cache.NewMsgCacheModel(rdb), cache.NewMsgCacheModel(rdb, config),
config.Config.Secret, config.Secret,
config.Config.TokenPolicy.Expire, config.TokenPolicy.Expire,
config,
) )
return func(c *gin.Context) { return func(c *gin.Context) {
switch c.Request.Method { switch c.Request.Method {
@ -241,7 +327,7 @@ func GinParseToken(rdb redis.UniversalClient) gin.HandlerFunc {
c.Abort() c.Abort()
return return
} }
claims, err := tokenverify.GetClaimFromToken(token, authverify.Secret()) claims, err := tokenverify.GetClaimFromToken(token, authverify.Secret(config.Secret))
if err != nil { if err != nil {
log.ZWarn(c, "jwt get token error", errs.ErrTokenUnknown.Wrap()) log.ZWarn(c, "jwt get token error", errs.ErrTokenUnknown.Wrap())
apiresp.GinError(c, 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) m, err := dataBase.GetTokensWithoutError(c, claims.UserID, claims.PlatformID)
if err != nil { if err != nil {
log.ZWarn(c, "cache get token error", errs.ErrTokenNotExist.Wrap())
apiresp.GinError(c, errs.ErrTokenNotExist.Wrap()) apiresp.GinError(c, errs.ErrTokenNotExist.Wrap())
c.Abort() c.Abort()
return return
} }
if len(m) == 0 { if len(m) == 0 {
log.ZWarn(c, "cache do not exist token error", errs.ErrTokenNotExist.Wrap())
apiresp.GinError(c, errs.ErrTokenNotExist.Wrap()) apiresp.GinError(c, errs.ErrTokenNotExist.Wrap())
c.Abort() c.Abort()
return return
@ -265,12 +349,10 @@ func GinParseToken(rdb redis.UniversalClient) gin.HandlerFunc {
switch v { switch v {
case constant.NormalToken: case constant.NormalToken:
case constant.KickedToken: case constant.KickedToken:
log.ZWarn(c, "cache kicked token error", errs.ErrTokenKicked.Wrap())
apiresp.GinError(c, errs.ErrTokenKicked.Wrap()) apiresp.GinError(c, errs.ErrTokenKicked.Wrap())
c.Abort() c.Abort()
return return
default: default:
log.ZWarn(c, "cache unknown token error", errs.ErrTokenUnknown.Wrap())
apiresp.GinError(c, errs.ErrTokenUnknown.Wrap()) apiresp.GinError(c, errs.ErrTokenUnknown.Wrap())
c.Abort() c.Abort()
return 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 package api
import ( import (
"github.com/gin-gonic/gin"
"github.com/OpenIMSDK/protocol/user" "github.com/OpenIMSDK/protocol/user"
"github.com/OpenIMSDK/tools/a2r" "github.com/OpenIMSDK/tools/a2r"
"github.com/gin-gonic/gin"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
) )

@ -19,15 +19,11 @@ import (
"net/http" "net/http"
"strconv" "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/protocol/third"
"github.com/OpenIMSDK/tools/a2r" "github.com/OpenIMSDK/tools/a2r"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/gin-gonic/gin"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "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) a2r.Call(third.ThirdClient.SearchLogs, o.Client, c)
} }
func GetPrometheus(c *gin.Context) { func (o *ThirdApi) GetPrometheus(c *gin.Context) {
c.Redirect(http.StatusFound, config2.Config.Prometheus.GrafanaUrl) c.Redirect(http.StatusFound, o.Config.Prometheus.GrafanaUrl)
} }

@ -23,8 +23,6 @@ import (
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "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) { func (u *UserApi) GetUsersOnlineStatus(c *gin.Context) {
var req msggateway.GetUsersOnlineStatusReq var req msggateway.GetUsersOnlineStatusReq
if err := c.BindJSON(&req); err != nil { if err := c.BindJSON(&req); err != nil {
apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) apiresp.GinError(c, err)
return return
} }
conns, err := u.Discov.GetConns(c, config.Config.RpcRegisterName.OpenImMessageGatewayName) conns, err := u.Discov.GetConns(c, u.Config.RpcRegisterName.OpenImMessageGatewayName)
if err != nil { if err != nil {
apiresp.GinError(c, err) apiresp.GinError(c, err)
return return
@ -86,7 +84,7 @@ func (u *UserApi) GetUsersOnlineStatus(c *gin.Context) {
msgClient := msggateway.NewMsgGatewayClient(v) msgClient := msggateway.NewMsgGatewayClient(v)
reply, err := msgClient.GetUsersOnlineStatus(c, &req) reply, err := msgClient.GetUsersOnlineStatus(c, &req)
if err != nil { if err != nil {
log.ZWarn(c, "GetUsersOnlineStatus rpc err", err) log.ZDebug(c, "GetUsersOnlineStatus rpc error", err)
parseError := apiresp.ParseError(err) parseError := apiresp.ParseError(err)
if parseError.ErrCode == errs.NoPermissionError { 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()) apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap())
return return
} }
conns, err := u.Discov.GetConns(c, config.Config.RpcRegisterName.OpenImMessageGatewayName) conns, err := u.Discov.GetConns(c, u.Config.RpcRegisterName.OpenImMessageGatewayName)
if err != nil { if err != nil {
apiresp.GinError(c, err) apiresp.GinError(c, err)
return return
@ -145,7 +143,7 @@ func (u *UserApi) GetUsersOnlineTokenDetail(c *gin.Context) {
msgClient := msggateway.NewMsgGatewayClient(v) msgClient := msggateway.NewMsgGatewayClient(v)
reply, err := msgClient.GetUsersOnlineStatus(c, &req) reply, err := msgClient.GetUsersOnlineStatus(c, &req)
if err != nil { if err != nil {
log.ZWarn(c, "GetUsersOnlineStatus rpc err", err) log.ZWarn(c, "GetUsersOnlineStatus rpc err", err)
continue continue
} else { } else {
wsResult = append(wsResult, reply.SuccessResult...) wsResult = append(wsResult, reply.SuccessResult...)

@ -20,18 +20,13 @@ import (
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/http" "github.com/openimsdk/open-im-server/v3/pkg/common/http"
) )
func callBackURL() string { func CallbackUserOnline(ctx context.Context, globalConfig *config.GlobalConfig, userID string, platformID int, isAppBackground bool, connID string) error {
return config.Config.Callback.CallbackUrl if !globalConfig.Callback.CallbackUserOnline.Enable {
}
func CallbackUserOnline(ctx context.Context, userID string, platformID int, isAppBackground bool, connID string) error {
if !config.Config.Callback.CallbackUserOnline.Enable {
return nil return nil
} }
req := cbapi.CallbackUserOnlineReq{ req := cbapi.CallbackUserOnlineReq{
@ -49,14 +44,14 @@ func CallbackUserOnline(ctx context.Context, userID string, platformID int, isAp
ConnID: connID, ConnID: connID,
} }
resp := cbapi.CommonCallbackResp{} resp := cbapi.CommonCallbackResp{}
if err := http.CallBackPostReturn(ctx, callBackURL(), &req, &resp, config.Config.Callback.CallbackUserOnline); err != nil { if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, &req, &resp, globalConfig.Callback.CallbackUserOnline); err != nil {
return err return err
} }
return nil return nil
} }
func CallbackUserOffline(ctx context.Context, userID string, platformID int, connID string) error { func CallbackUserOffline(ctx context.Context, globalConfig *config.GlobalConfig, userID string, platformID int, connID string) error {
if !config.Config.Callback.CallbackUserOffline.Enable { if !globalConfig.Callback.CallbackUserOffline.Enable {
return nil return nil
} }
req := &cbapi.CallbackUserOfflineReq{ req := &cbapi.CallbackUserOfflineReq{
@ -73,14 +68,14 @@ func CallbackUserOffline(ctx context.Context, userID string, platformID int, con
ConnID: connID, ConnID: connID,
} }
resp := &cbapi.CallbackUserOfflineResp{} resp := &cbapi.CallbackUserOfflineResp{}
if err := http.CallBackPostReturn(ctx, callBackURL(), req, resp, config.Config.Callback.CallbackUserOffline); err != nil { if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackUserOffline); err != nil {
return err return err
} }
return nil return nil
} }
func CallbackUserKickOff(ctx context.Context, userID string, platformID int) error { func CallbackUserKickOff(ctx context.Context, globalConfig *config.GlobalConfig, userID string, platformID int) error {
if !config.Config.Callback.CallbackUserKickOff.Enable { if !globalConfig.Callback.CallbackUserKickOff.Enable {
return nil return nil
} }
req := &cbapi.CallbackUserKickOffReq{ req := &cbapi.CallbackUserKickOffReq{
@ -96,7 +91,7 @@ func CallbackUserKickOff(ctx context.Context, userID string, platformID int) err
Seq: time.Now().UnixMilli(), Seq: time.Now().UnixMilli(),
} }
resp := &cbapi.CommonCallbackResp{} resp := &cbapi.CommonCallbackResp{}
if err := http.CallBackPostReturn(ctx, callBackURL(), req, resp, config.Config.Callback.CallbackUserOffline); err != nil { if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackUserOffline); err != nil {
return err return err
} }
return nil return nil

@ -22,16 +22,15 @@ import (
"sync" "sync"
"sync/atomic" "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/constant"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/apiresp" "github.com/OpenIMSDK/tools/apiresp"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
"google.golang.org/protobuf/proto"
) )
var ( var (
@ -76,25 +75,20 @@ type Client struct {
token string token string
} }
func newClient(ctx *UserConnContext, conn LongConn, isCompress bool) *Client { // function not used
return &Client{ // func newClient(ctx *UserConnContext, conn LongConn, isCompress bool) *Client {
w: new(sync.Mutex), // return &Client{
conn: conn, // w: new(sync.Mutex),
PlatformID: utils.StringToInt(ctx.GetPlatformID()), // conn: conn,
IsCompress: isCompress, // PlatformID: utils.StringToInt(ctx.GetPlatformID()),
UserID: ctx.GetUserID(), // IsCompress: isCompress,
ctx: ctx, // UserID: ctx.GetUserID(),
} // ctx: ctx,
} // }
// }
// ResetClient updates the client's state with new connection and context information. // ResetClient updates the client's state with new connection and context information.
func (c *Client) ResetClient( func (c *Client) ResetClient(ctx *UserConnContext, conn LongConn, isBackground, isCompress bool, longConnServer LongConnServer, token string) {
ctx *UserConnContext,
conn LongConn,
isBackground, isCompress bool,
longConnServer LongConnServer,
token string,
) {
c.w = new(sync.Mutex) c.w = new(sync.Mutex)
c.conn = conn c.conn = conn
c.PlatformID = utils.StringToInt(ctx.GetPlatformID()) c.PlatformID = utils.StringToInt(ctx.GetPlatformID())
@ -109,9 +103,11 @@ func (c *Client) ResetClient(
c.token = token c.token = token
} }
// pingHandler handles ping messages and sends pong responses.
func (c *Client) pingHandler(_ string) error { func (c *Client) pingHandler(_ string) error {
_ = c.conn.SetReadDeadline(pongWait) if err := c.conn.SetReadDeadline(pongWait); err != nil {
return err
}
return c.writePongMsg() return c.writePongMsg()
} }
@ -138,7 +134,8 @@ func (c *Client) readMessage() {
} }
log.ZDebug(c.ctx, "readMessage", "messageType", messageType) 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 c.closedErr = ErrConnClosed
return return
} }
@ -173,7 +170,7 @@ func (c *Client) handleMessage(message []byte) error {
var err error var err error
message, err = c.longConnServer.DecompressWithPool(message) message, err = c.longConnServer.DecompressWithPool(message)
if err != nil { 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) err := c.longConnServer.Decode(message, binaryReq)
if err != nil { if err != nil {
return utils.Wrap(err, "") return err
} }
if err := c.longConnServer.Validate(binaryReq); err != nil { if err := c.longConnServer.Validate(binaryReq); err != nil {
return utils.Wrap(err, "") return err
} }
if binaryReq.SendID != c.UserID { 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( ctx := mcontext.WithMustInfoCtx(
@ -236,7 +233,7 @@ func (c *Client) setAppBackgroundStatus(ctx context.Context, req *Req) ([]byte,
} }
c.IsBackground = isBackground c.IsBackground = isBackground
// todo callback // TODO: callback
return resp, nil return resp, nil
} }
@ -270,7 +267,7 @@ func (c *Client) replyMessage(ctx context.Context, binaryReq *Req, err error, re
} }
if binaryReq.ReqIdentifier == WsLogoutMsg { if binaryReq.ReqIdentifier == WsLogoutMsg {
return errors.New("user logout") return errs.Wrap(errors.New("user logout"))
} }
return nil return nil
} }
@ -313,17 +310,21 @@ func (c *Client) writeBinaryMsg(resp Resp) error {
encodedBuf, err := c.longConnServer.Encode(resp) encodedBuf, err := c.longConnServer.Encode(resp)
if err != nil { if err != nil {
return utils.Wrap(err, "") return err
} }
c.w.Lock() c.w.Lock()
defer c.w.Unlock() defer c.w.Unlock()
_ = c.conn.SetWriteDeadline(writeWait) err = c.conn.SetWriteDeadline(writeWait)
if err != nil {
return err
}
if c.IsCompress { if c.IsCompress {
resultBuf, compressErr := c.longConnServer.CompressWithPool(encodedBuf) resultBuf, compressErr := c.longConnServer.CompressWithPool(encodedBuf)
if compressErr != nil { if compressErr != nil {
return utils.Wrap(compressErr, "") return compressErr
} }
return c.conn.WriteMessage(MessageBinary, resultBuf) return c.conn.WriteMessage(MessageBinary, resultBuf)
} }
@ -341,7 +342,7 @@ func (c *Client) writePongMsg() error {
err := c.conn.SetWriteDeadline(writeWait) err := c.conn.SetWriteDeadline(writeWait)
if err != nil { if err != nil {
return utils.Wrap(err, "") return err
} }
return c.conn.WriteMessage(PongMessage, nil) return c.conn.WriteMessage(PongMessage, nil)

@ -17,11 +17,10 @@ package msggateway
import ( import (
"bytes" "bytes"
"compress/gzip" "compress/gzip"
"errors"
"io" "io"
"sync" "sync"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/errs"
) )
var ( var (
@ -46,12 +45,15 @@ func NewGzipCompressor() *GzipCompressor {
func (g *GzipCompressor) Compress(rawData []byte) ([]byte, error) { func (g *GzipCompressor) Compress(rawData []byte) ([]byte, error) {
gzipBuffer := bytes.Buffer{} gzipBuffer := bytes.Buffer{}
gz := gzip.NewWriter(&gzipBuffer) gz := gzip.NewWriter(&gzipBuffer)
if _, err := gz.Write(rawData); err != nil { 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 { 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 return gzipBuffer.Bytes(), nil
} }
@ -63,10 +65,10 @@ func (g *GzipCompressor) CompressWithPool(rawData []byte) ([]byte, error) {
gz.Reset(&gzipBuffer) gz.Reset(&gzipBuffer)
if _, err := gz.Write(rawData); err != nil { 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 { 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 return gzipBuffer.Bytes(), nil
} }
@ -75,32 +77,36 @@ func (g *GzipCompressor) DeCompress(compressedData []byte) ([]byte, error) {
buff := bytes.NewBuffer(compressedData) buff := bytes.NewBuffer(compressedData)
reader, err := gzip.NewReader(buff) reader, err := gzip.NewReader(buff)
if err != nil { 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 { if err != nil {
return nil, utils.Wrap(err, "ReadAll failed") return nil, errs.Wrap(err, "GzipCompressor.DeCompress: reading from gzip reader failed")
} }
_ = reader.Close() if err = reader.Close(); err != nil {
return compressedData, 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) { func (g *GzipCompressor) DecompressWithPool(compressedData []byte) ([]byte, error) {
reader := gzipReaderPool.Get().(*gzip.Reader) reader := gzipReaderPool.Get().(*gzip.Reader)
if reader == nil {
return nil, errors.New("NewReader failed")
}
defer gzipReaderPool.Put(reader) defer gzipReaderPool.Put(reader)
err := reader.Reset(bytes.NewReader(compressedData)) err := reader.Reset(bytes.NewReader(compressedData))
if err != nil { 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 { 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 decompressedData, nil
return compressedData, nil
} }

@ -37,10 +37,16 @@ func TestCompressDecompress(t *testing.T) {
// compress // compress
dest, err := compressor.CompressWithPool(src) dest, err := compressor.CompressWithPool(src)
if err != nil {
t.Log(err)
}
assert.Equal(t, nil, err) assert.Equal(t, nil, err)
// decompress // decompress
res, err := compressor.DecompressWithPool(dest) res, err := compressor.DecompressWithPool(dest)
if err != nil {
t.Log(err)
}
assert.Equal(t, nil, err) assert.Equal(t, nil, err)
// check // check
@ -60,10 +66,16 @@ func TestCompressDecompressWithConcurrency(t *testing.T) {
// compress // compress
dest, err := compressor.CompressWithPool(src) dest, err := compressor.CompressWithPool(src)
if err != nil {
t.Log(err)
}
assert.Equal(t, nil, err) assert.Equal(t, nil, err)
// decompress // decompress
res, err := compressor.DecompressWithPool(dest) res, err := compressor.DecompressWithPool(dest)
if err != nil {
t.Log(err)
}
assert.Equal(t, nil, err) assert.Equal(t, nil, err)
// check // check
@ -99,6 +111,7 @@ func BenchmarkDecompress(b *testing.B) {
compressor := NewGzipCompressor() compressor := NewGzipCompressor()
comdata, err := compressor.Compress(src) comdata, err := compressor.Compress(src)
assert.Equal(b, nil, err) assert.Equal(b, nil, err)
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {

@ -18,7 +18,7 @@ import (
"bytes" "bytes"
"encoding/gob" "encoding/gob"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/errs"
) )
type Encoder interface { type Encoder interface {
@ -37,7 +37,7 @@ func (g *GobEncoder) Encode(data any) ([]byte, error) {
enc := gob.NewEncoder(&buff) enc := gob.NewEncoder(&buff)
err := enc.Encode(data) err := enc.Encode(data)
if err != nil { if err != nil {
return nil, err return nil, errs.Wrap(err, "GobEncoder.Encode failed")
} }
return buff.Bytes(), nil return buff.Bytes(), nil
} }
@ -47,7 +47,7 @@ func (g *GobEncoder) Decode(encodeData []byte, decodeData any) error {
dec := gob.NewDecoder(buff) dec := gob.NewDecoder(buff)
err := dec.Decode(decodeData) err := dec.Decode(decodeData)
if err != nil { if err != nil {
return utils.Wrap(err, "") return errs.Wrap(err, "GobEncoder.Decode failed")
} }
return nil return nil
} }

@ -17,8 +17,6 @@ package msggateway
import ( import (
"context" "context"
"google.golang.org/grpc"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/msggateway" "github.com/OpenIMSDK/protocol/msggateway"
"github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/discoveryregistry"
@ -26,31 +24,32 @@ import (
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc" "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 { func (s *Server) InitServer(config *config.GlobalConfig, disCov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
rdb, err := cache.NewRedis() rdb, err := cache.NewRedis(config)
if err != nil { if err != nil {
return err return err
} }
msgModel := cache.NewMsgCacheModel(rdb) msgModel := cache.NewMsgCacheModel(rdb, config)
s.LongConnServer.SetDiscoveryRegistry(disCov) s.LongConnServer.SetDiscoveryRegistry(disCov, config)
s.LongConnServer.SetCacheHandler(msgModel) s.LongConnServer.SetCacheHandler(msgModel)
msggateway.RegisterMsgGatewayServer(server, s) msggateway.RegisterMsgGatewayServer(server, s)
return nil return nil
} }
func (s *Server) Start() error { func (s *Server) Start(conf *config.GlobalConfig) error {
return startrpc.Start( return startrpc.Start(
s.rpcPort, s.rpcPort,
config.Config.RpcRegisterName.OpenImMessageGatewayName, conf.RpcRegisterName.OpenImMessageGatewayName,
s.prometheusPort, s.prometheusPort,
conf,
s.InitServer, s.InitServer,
) )
} }
@ -60,18 +59,20 @@ type Server struct {
prometheusPort int prometheusPort int
LongConnServer LongConnServer LongConnServer LongConnServer
pushTerminal []int pushTerminal []int
config *config.GlobalConfig
} }
func (s *Server) SetLongConnServer(LongConnServer LongConnServer) { func (s *Server) SetLongConnServer(LongConnServer LongConnServer) {
s.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{ return &Server{
rpcPort: rpcPort, rpcPort: rpcPort,
prometheusPort: proPort, prometheusPort: proPort,
LongConnServer: longConnServer, LongConnServer: longConnServer,
pushTerminal: []int{constant.IOSPlatformID, constant.AndroidPlatformID}, pushTerminal: []int{constant.IOSPlatformID, constant.AndroidPlatformID},
config: config,
} }
} }
@ -86,7 +87,7 @@ func (s *Server) GetUsersOnlineStatus(
ctx context.Context, ctx context.Context,
req *msggateway.GetUsersOnlineStatusReq, req *msggateway.GetUsersOnlineStatusReq,
) (*msggateway.GetUsersOnlineStatusResp, error) { ) (*msggateway.GetUsersOnlineStatusResp, error) {
if !authverify.IsAppManagerUid(ctx) { if !authverify.IsAppManagerUid(ctx, s.config) {
return nil, errs.ErrNoPermission.Wrap("only app manager") return nil, errs.ErrNoPermission.Wrap("only app manager")
} }
var resp msggateway.GetUsersOnlineStatusResp var resp msggateway.GetUsersOnlineStatusResp

@ -22,33 +22,25 @@ import (
) )
// RunWsAndServer run ws server. // RunWsAndServer run ws server.
func RunWsAndServer(rpcPort, wsPort, prometheusPort int) error { func RunWsAndServer(conf *config.GlobalConfig, rpcPort, wsPort, prometheusPort int) error {
fmt.Println( fmt.Println("start rpc/msg_gateway server, port: ", rpcPort, wsPort, prometheusPort, ", OpenIM version: ", config.Version)
"start rpc/msg_gateway server, port: ",
rpcPort,
wsPort,
prometheusPort,
", OpenIM version: ",
config.Version,
)
longServer, err := NewWsServer( longServer, err := NewWsServer(
conf,
WithPort(wsPort), WithPort(wsPort),
WithMaxConnNum(int64(config.Config.LongConnSvr.WebsocketMaxConnNum)), WithMaxConnNum(int64(conf.LongConnSvr.WebsocketMaxConnNum)),
WithHandshakeTimeout(time.Duration(config.Config.LongConnSvr.WebsocketTimeout)*time.Second), WithHandshakeTimeout(time.Duration(conf.LongConnSvr.WebsocketTimeout)*time.Second),
WithMessageMaxMsgLength(config.Config.LongConnSvr.WebsocketMaxMsgLen), WithMessageMaxMsgLength(conf.LongConnSvr.WebsocketMaxMsgLen),
WithWriteBufferSize(config.Config.LongConnSvr.WebsocketWriteBufferSize), WithWriteBufferSize(conf.LongConnSvr.WebsocketWriteBufferSize),
) )
if err != nil { if err != nil {
return err return err
} }
hubServer := NewServer(rpcPort, prometheusPort, longServer) hubServer := NewServer(rpcPort, prometheusPort, longServer, conf)
netDone := make(chan error) netDone := make(chan error)
go func() { go func() {
err = hubServer.Start() err = hubServer.Start(conf)
if err != nil { netDone <- err
netDone <- err
}
}() }()
return hubServer.LongConnServer.Run(netDone) return hubServer.LongConnServer.Run(netDone)
} }

@ -15,9 +15,11 @@
package msggateway package msggateway
import ( import (
"errors"
"net/http" "net/http"
"time" "time"
"github.com/OpenIMSDK/tools/errs"
"github.com/gorilla/websocket" "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) conn, err := upgrader.Upgrade(w, r, nil)
if err != 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 d.conn = conn
return nil return nil
@ -96,7 +99,16 @@ func (d *GWebSocket) SetReadDeadline(timeout time.Duration) error {
} }
func (d *GWebSocket) SetWriteDeadline(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) { 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 { func (d *GWebSocket) IsNil() bool {
if d.conn != nil { return d.conn == nil
return false //
} // if d.conn != nil {
return true // return false
// }
// return true
} }
func (d *GWebSocket) SetConnNil() { func (d *GWebSocket) SetConnNil() {

@ -18,17 +18,16 @@ import (
"context" "context"
"sync" "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/msg"
"github.com/OpenIMSDK/protocol/push"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/utils" "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" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"google.golang.org/protobuf/proto"
) )
type Req struct { type Req struct {
@ -107,9 +106,9 @@ type GrpcHandler struct {
validate *validator.Validate validate *validator.Validate
} }
func NewGrpcHandler(validate *validator.Validate, client discoveryregistry.SvcDiscoveryRegistry) *GrpcHandler { func NewGrpcHandler(validate *validator.Validate, client discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *GrpcHandler {
msgRpcClient := rpcclient.NewMessageRpcClient(client) msgRpcClient := rpcclient.NewMessageRpcClient(client, config)
pushRpcClient := rpcclient.NewPushRpcClient(client) pushRpcClient := rpcclient.NewPushRpcClient(client, config)
return &GrpcHandler{ return &GrpcHandler{
msgRpcClient: &msgRpcClient, msgRpcClient: &msgRpcClient,
pushClient: &pushRpcClient, validate: validate, 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) { func (g GrpcHandler) GetSeq(context context.Context, data *Req) ([]byte, error) {
req := sdkws.GetMaxSeqReq{} req := sdkws.GetMaxSeqReq{}
if err := proto.Unmarshal(data.Data, &req); err != nil { 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 { 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) resp, err := g.msgRpcClient.GetMaxSeq(context, &req)
if err != nil { if err != nil {
@ -130,28 +129,37 @@ func (g GrpcHandler) GetSeq(context context.Context, data *Req) ([]byte, error)
} }
c, err := proto.Marshal(resp) c, err := proto.Marshal(resp)
if err != nil { if err != nil {
return nil, err return nil, errs.Wrap(err, "GetSeq: error marshaling response")
} }
return c, nil return c, nil
} }
func (g GrpcHandler) SendMessage(context context.Context, data *Req) ([]byte, error) { // SendMessage handles the sending of messages through gRPC. It unmarshals the request data,
msgData := sdkws.MsgData{} // 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 { 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 { 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} req := msg.SendMsgReq{MsgData: &msgData}
resp, err := g.msgRpcClient.SendMsg(context, &req)
resp, err := g.msgRpcClient.SendMsg(ctx, &req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
c, err := proto.Marshal(resp) c, err := proto.Marshal(resp)
if err != nil { if err != nil {
return nil, err return nil, errs.Wrap(err, "error marshaling response")
} }
return c, nil return c, nil
} }
@ -162,7 +170,7 @@ func (g GrpcHandler) SendSignalMessage(context context.Context, data *Req) ([]by
} }
c, err := proto.Marshal(resp) c, err := proto.Marshal(resp)
if err != nil { if err != nil {
return nil, err return nil, errs.Wrap(err, "error marshaling response")
} }
return c, nil 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) { func (g GrpcHandler) PullMessageBySeqList(context context.Context, data *Req) ([]byte, error) {
req := sdkws.PullMessageBySeqsReq{} req := sdkws.PullMessageBySeqsReq{}
if err := proto.Unmarshal(data.Data, &req); err != nil { 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 { 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) resp, err := g.msgRpcClient.PullMessageBySeqList(context, &req)
if err != nil { if err != nil {
@ -181,7 +189,7 @@ func (g GrpcHandler) PullMessageBySeqList(context context.Context, data *Req) ([
} }
c, err := proto.Marshal(resp) c, err := proto.Marshal(resp)
if err != nil { if err != nil {
return nil, err return nil, errs.Wrap(err, "error marshaling response")
} }
return c, nil 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) { func (g GrpcHandler) UserLogout(context context.Context, data *Req) ([]byte, error) {
req := push.DelUserPushTokenReq{} req := push.DelUserPushTokenReq{}
if err := proto.Unmarshal(data.Data, &req); err != nil { 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) resp, err := g.pushClient.DelUserPushToken(context, &req)
if err != nil { if err != nil {
@ -197,7 +205,7 @@ func (g GrpcHandler) UserLogout(context context.Context, data *Req) ([]byte, err
} }
c, err := proto.Marshal(resp) c, err := proto.Marshal(resp)
if err != nil { if err != nil {
return nil, err return nil, errs.Wrap(err, "error marshaling response")
} }
return c, nil 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) { func (g GrpcHandler) SetUserDeviceBackground(_ context.Context, data *Req) ([]byte, bool, error) {
req := sdkws.SetAppBackgroundStatusReq{} req := sdkws.SetAppBackgroundStatusReq{}
if err := proto.Unmarshal(data.Data, &req); err != nil { 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 { 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 return nil, req.IsBackground, nil
} }

@ -25,24 +25,21 @@ import (
"sync/atomic" "sync/atomic"
"time" "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/constant"
"github.com/OpenIMSDK/protocol/msggateway" "github.com/OpenIMSDK/protocol/msggateway"
"github.com/OpenIMSDK/tools/apiresp"
"github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/utils" "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/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/redis/go-redis/v9"
"golang.org/x/sync/errgroup"
) )
type LongConnServer interface { type LongConnServer interface {
@ -52,7 +49,7 @@ type LongConnServer interface {
GetUserPlatformCons(userID string, platform int) ([]*Client, bool, bool) GetUserPlatformCons(userID string, platform int) ([]*Client, bool, bool)
Validate(s any) error Validate(s any) error
SetCacheHandler(cache cache.MsgModel) SetCacheHandler(cache cache.MsgModel)
SetDiscoveryRegistry(client discoveryregistry.SvcDiscoveryRegistry) SetDiscoveryRegistry(client discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig)
KickUserConn(client *Client) error KickUserConn(client *Client) error
UnRegister(c *Client) UnRegister(c *Client)
SetKickHandlerInfo(i *kickHandler) SetKickHandlerInfo(i *kickHandler)
@ -61,13 +58,15 @@ type LongConnServer interface {
MessageHandler MessageHandler
} }
var bufferPool = sync.Pool{ // bufferPool is unused
New: func() any { // var bufferPool = sync.Pool{
return make([]byte, 1024) // New: func() any {
}, // return make([]byte, 1024)
} // },
// }
type WsServer struct { type WsServer struct {
globalConfig *config.GlobalConfig
port int port int
wsMaxConnNum int64 wsMaxConnNum int64
registerChan chan *Client registerChan chan *Client
@ -87,15 +86,16 @@ type WsServer struct {
Encoder Encoder
MessageHandler MessageHandler
} }
type kickHandler struct { type kickHandler struct {
clientOK bool clientOK bool
oldClients []*Client oldClients []*Client
newClient *Client newClient *Client
} }
func (ws *WsServer) SetDiscoveryRegistry(disCov discoveryregistry.SvcDiscoveryRegistry) { func (ws *WsServer) SetDiscoveryRegistry(disCov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) {
ws.MessageHandler = NewGrpcHandler(ws.validate, disCov) ws.MessageHandler = NewGrpcHandler(ws.validate, disCov, config)
u := rpcclient.NewUserRpcClient(disCov) u := rpcclient.NewUserRpcClient(disCov, config)
ws.userClient = &u ws.userClient = &u
ws.disCov = disCov ws.disCov = disCov
} }
@ -107,12 +107,12 @@ func (ws *WsServer) SetUserOnlineStatus(ctx context.Context, client *Client, sta
} }
switch status { switch status {
case constant.Online: 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 { if err != nil {
log.ZWarn(ctx, "CallbackUserOnline err", err) log.ZWarn(ctx, "CallbackUserOnline err", err)
} }
case constant.Offline: 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 { if err != nil {
log.ZWarn(ctx, "CallbackUserOffline err", err) log.ZWarn(ctx, "CallbackUserOffline err", err)
} }
@ -128,7 +128,9 @@ func (ws *WsServer) UnRegister(c *Client) {
} }
func (ws *WsServer) Validate(s any) error { func (ws *WsServer) Validate(s any) error {
//?question? if s == nil {
return errs.Wrap(errors.New("input cannot be nil"))
}
return nil return nil
} }
@ -140,13 +142,14 @@ func (ws *WsServer) GetUserPlatformCons(userID string, platform int) ([]*Client,
return ws.clients.Get(userID, platform) return ws.clients.Get(userID, platform)
} }
func NewWsServer(opts ...Option) (*WsServer, error) { func NewWsServer(globalConfig *config.GlobalConfig, opts ...Option) (*WsServer, error) {
var config configs var config configs
for _, o := range opts { for _, o := range opts {
o(&config) o(&config)
} }
v := validator.New() v := validator.New()
return &WsServer{ return &WsServer{
globalConfig: globalConfig,
port: config.port, port: config.port,
wsMaxConnNum: config.maxConnNum, wsMaxConnNum: config.maxConnNum,
writeBufferSize: config.writeBufferSize, writeBufferSize: config.writeBufferSize,
@ -220,7 +223,7 @@ func (ws *WsServer) Run(done chan error) error {
var concurrentRequest = 3 var concurrentRequest = 3
func (ws *WsServer) sendUserOnlineInfoToOtherNode(ctx context.Context, client *Client) error { func (ws *WsServer) sendUserOnlineInfoToOtherNode(ctx context.Context, client *Client) error {
conns, err := ws.disCov.GetConns(ctx, config.Config.RpcRegisterName.OpenImMessageGatewayName) conns, err := ws.disCov.GetConns(ctx, ws.globalConfig.RpcRegisterName.OpenImMessageGatewayName)
if err != nil { if err != nil {
return err return err
} }
@ -275,7 +278,7 @@ func (ws *WsServer) registerClient(client *Client) {
log.ZDebug(client.ctx, "user exist", "userID", client.UserID, "platformID", client.PlatformID) log.ZDebug(client.ctx, "user exist", "userID", client.UserID, "platformID", client.PlatformID)
if clientOK { if clientOK {
ws.clients.Set(client.UserID, client) 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)) log.ZInfo(client.ctx, "repeat login", "userID", client.UserID, "platformID", client.PlatformID, "old remote addr", getRemoteAdders(oldClients))
ws.onlineUserConnNum.Add(1) ws.onlineUserConnNum.Add(1)
} else { } else {
@ -285,7 +288,7 @@ func (ws *WsServer) registerClient(client *Client) {
} }
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
if config.Config.Envs.Discovery == "zookeeper" { if ws.globalConfig.Envs.Discovery == "zookeeper" {
wg.Add(1) wg.Add(1)
go func() { go func() {
defer wg.Done() defer wg.Done()
@ -328,7 +331,7 @@ func (ws *WsServer) KickUserConn(client *Client) error {
} }
func (ws *WsServer) multiTerminalLoginChecker(clientOK bool, oldClients []*Client, newClient *Client) { func (ws *WsServer) multiTerminalLoginChecker(clientOK bool, oldClients []*Client, newClient *Client) {
switch config.Config.MultiLoginPolicy { switch ws.globalConfig.MultiLoginPolicy {
case constant.DefalutNotKick: case constant.DefalutNotKick:
case constant.PCAndOther: case constant.PCAndOther:
if constant.PlatformIDToClass(newClient.PlatformID) == constant.TerminalPC { 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") return nil, errs.ErrConnArgsErr.Wrap("platformID is not int")
} }
v.PlatformID = platformID 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 return nil, err
} }
if query.Get(Compression) == GzipCompressionProtocol { if query.Get(Compression) == GzipCompressionProtocol {

@ -19,15 +19,15 @@ import "time"
type ( type (
Option func(opt *configs) Option func(opt *configs)
configs struct { configs struct {
// 长连接监听端口 // Long connection listening port
port int port int
// 长连接允许最大链接数 // Maximum number of connections allowed for long connection
maxConnNum int64 maxConnNum int64
// 连接握手超时时间 // Connection handshake timeout
handshakeTimeout time.Duration handshakeTimeout time.Duration
// 允许消息最大长度 // Maximum length allowed for messages
messageMaxMsgLength int messageMaxMsgLength int
// websocket write buffer, default: 4096, 4kb. // Websocket write buffer, default: 4096, 4kb.
writeBufferSize int 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) { func (u *UserMap) Set(key string, v *Client) {
allClients, existed := u.m.Load(key) allClients, existed := u.m.Load(key)
if existed { 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 := allClients.([]*Client)
oldClients = append(oldClients, v) oldClients = append(oldClients, v)
u.m.Store(key, oldClients) u.m.Store(key, oldClients)
} else { } 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 var clients []*Client
clients = append(clients, v) clients = append(clients, v)
u.m.Store(key, clients) u.m.Store(key, clients)

@ -18,24 +18,13 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
util "github.com/openimsdk/open-im-server/v3/pkg/util/genutil"
"net/http" "net/http"
"os" "os"
"os/signal" "os/signal"
"syscall" "syscall"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/mw" "github.com/OpenIMSDK/tools/mw"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/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/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
@ -43,22 +32,34 @@ import (
kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister" kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "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 { type MsgTransfer struct {
historyCH *OnlineHistoryRedisConsumerHandler // 这个消费者聚合消息, 订阅的topicws2ms_chat, 修改通知发往msg_to_modify topic, 消息存入redis后Incr Redis, 再发消息到ms2pschat topic推送 发消息到msg_to_mongo topic持久化 // This consumer aggregated messages, subscribed to the topic:ws2ms_chat,
historyMongoCH *OnlineHistoryMongoConsumerHandler // mongoDB批量插入, 成功后删除redis中消息以及处理删除通知消息删除的 订阅的topic: msg_to_mongo // the modification notification is sent to msg_to_modify topic, the message is stored in redis, Incr Redis,
ctx context.Context // and then the message is sent to ms2pschat topic for push, and the message is sent to msg_to_mongo topic for persistence
cancel context.CancelFunc 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 { func StartTransfer(config *config.GlobalConfig, prometheusPort int) error {
rdb, err := cache.NewRedis() rdb, err := cache.NewRedis(config)
if err != nil { if err != nil {
return err return err
} }
mongo, err := unrelation.NewMongo() mongo, err := unrelation.NewMongo(config)
if err != nil { if err != nil {
return err return err
} }
@ -66,36 +67,42 @@ func StartTransfer(prometheusPort int) error {
if err = mongo.CreateMsgIndex(); err != nil { if err = mongo.CreateMsgIndex(); err != nil {
return err return err
} }
client, err := kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery) client, err := kdisc.NewDiscoveryRegister(config)
if err != nil { if err != nil {
return err return err
} }
if err := client.CreateRpcRootNodes(config.Config.GetServiceNames()); err != nil { if err := client.CreateRpcRootNodes(config.GetServiceNames()); err != nil {
return err return err
} }
client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) client.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")))
msgModel := cache.NewMsgCacheModel(rdb) msgModel := cache.NewMsgCacheModel(rdb, config)
msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase()) msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase(config.Mongo.Database))
msgDatabase, err := controller.NewCommonMsgDatabase(msgDocModel, msgModel) msgDatabase, err := controller.NewCommonMsgDatabase(msgDocModel, msgModel, config)
if err != nil { if err != nil {
return err return err
} }
conversationRpcClient := rpcclient.NewConversationRpcClient(client) conversationRpcClient := rpcclient.NewConversationRpcClient(client, config)
groupRpcClient := rpcclient.NewGroupRpcClient(client) groupRpcClient := rpcclient.NewGroupRpcClient(client, config)
msgTransfer, err := NewMsgTransfer(msgDatabase, &conversationRpcClient, &groupRpcClient) msgTransfer, err := NewMsgTransfer(config, msgDatabase, &conversationRpcClient, &groupRpcClient)
if err != nil { if err != nil {
return err return err
} }
return msgTransfer.Start(prometheusPort) return msgTransfer.Start(prometheusPort, config)
} }
func NewMsgTransfer(msgDatabase controller.CommonMsgDatabase, conversationRpcClient *rpcclient.ConversationRpcClient, groupRpcClient *rpcclient.GroupRpcClient) (*MsgTransfer, error) { func NewMsgTransfer(
historyCH, err := NewOnlineHistoryRedisConsumerHandler(msgDatabase, conversationRpcClient, groupRpcClient) config *config.GlobalConfig,
msgDatabase controller.CommonMsgDatabase,
conversationRpcClient *rpcclient.ConversationRpcClient,
groupRpcClient *rpcclient.GroupRpcClient,
) (*MsgTransfer, error) {
historyCH, err := NewOnlineHistoryRedisConsumerHandler(config, msgDatabase, conversationRpcClient, groupRpcClient)
if err != nil { if err != nil {
return nil, err return nil, err
} }
historyMongoCH, err := NewOnlineHistoryMongoConsumerHandler(msgDatabase) historyMongoCH, err := NewOnlineHistoryMongoConsumerHandler(config, msgDatabase)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -103,10 +110,11 @@ func NewMsgTransfer(msgDatabase controller.CommonMsgDatabase, conversationRpcCli
return &MsgTransfer{ return &MsgTransfer{
historyCH: historyCH, historyCH: historyCH,
historyMongoCH: historyMongoCH, historyMongoCH: historyMongoCH,
config: config,
}, nil }, 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) fmt.Println("start msg transfer", "prometheusPort:", prometheusPort)
if prometheusPort <= 0 { if prometheusPort <= 0 {
return errs.Wrap(errors.New("prometheusPort not correct")) return errs.Wrap(errors.New("prometheusPort not correct"))
@ -118,19 +126,16 @@ func (m *MsgTransfer) Start(prometheusPort int) error {
netErr error netErr error
) )
onError := func(ctx context.Context, err error, errInfo string) { go m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyCH)
log.ZWarn(ctx, errInfo, err) go m.historyMongoCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyMongoCH)
}
go m.historyCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyCH, onError)
go m.historyMongoCH.historyConsumerGroup.RegisterHandleAndConsumer(m.ctx, m.historyMongoCH, onError)
if config.Config.Prometheus.Enable { if config.Prometheus.Enable {
go func() { go func() {
proreg := prometheus.NewRegistry() proreg := prometheus.NewRegistry()
proreg.MustRegister( proreg.MustRegister(
collectors.NewGoCollector(), collectors.NewGoCollector(),
) )
proreg.MustRegister(prommetrics.GetGrpcCusMetrics("Transfer")...) proreg.MustRegister(prommetrics.GetGrpcCusMetrics("Transfer", config)...)
http.Handle("/metrics", promhttp.HandlerFor(proreg, promhttp.HandlerOpts{Registry: proreg})) http.Handle("/metrics", promhttp.HandlerFor(proreg, promhttp.HandlerOpts{Registry: proreg}))
err := http.ListenAndServe(fmt.Sprintf(":%d", prometheusPort), nil) err := http.ListenAndServe(fmt.Sprintf(":%d", prometheusPort), nil)
if err != nil && err != http.ErrServerClosed { if err != nil && err != http.ErrServerClosed {
@ -144,12 +149,12 @@ func (m *MsgTransfer) Start(prometheusPort int) error {
signal.Notify(sigs, syscall.SIGTERM) signal.Notify(sigs, syscall.SIGTERM)
select { select {
case <-sigs: case <-sigs:
util.SIGUSR1Exit() util.SIGTERMExit()
// graceful close kafka client. // graceful close kafka client.
m.cancel() m.cancel()
m.historyCH.historyConsumerGroup.Close() m.historyCH.historyConsumerGroup.Close()
m.historyMongoCH.historyConsumerGroup.Close() m.historyMongoCH.historyConsumerGroup.Close()
return nil
case <-netDone: case <-netDone:
m.cancel() m.cancel()
m.historyCH.historyConsumerGroup.Close() m.historyCH.historyConsumerGroup.Close()
@ -157,6 +162,4 @@ func (m *MsgTransfer) Start(prometheusPort int) error {
close(netDone) close(netDone)
return netErr return netErr
} }
return nil
} }

@ -22,24 +22,20 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
"github.com/OpenIMSDK/tools/errs"
"github.com/IBM/sarama" "github.com/IBM/sarama"
"github.com/go-redis/redis"
"google.golang.org/protobuf/proto"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/go-redis/redis"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "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/common/kafka"
"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"
"google.golang.org/protobuf/proto"
) )
const ( const (
@ -74,10 +70,10 @@ type OnlineHistoryRedisConsumerHandler struct {
chArrays [ChannelNum]chan Cmd2Value chArrays [ChannelNum]chan Cmd2Value
msgDistributionCh chan Cmd2Value msgDistributionCh chan Cmd2Value
singleMsgSuccessCount uint64 // singleMsgSuccessCount uint64
singleMsgFailedCount uint64 // singleMsgFailedCount uint64
singleMsgSuccessCountMutex sync.Mutex // singleMsgSuccessCountMutex sync.Mutex
singleMsgFailedCountMutex sync.Mutex // singleMsgFailedCountMutex sync.Mutex
msgDatabase controller.CommonMsgDatabase msgDatabase controller.CommonMsgDatabase
conversationRpcClient *rpcclient.ConversationRpcClient conversationRpcClient *rpcclient.ConversationRpcClient
@ -85,6 +81,7 @@ type OnlineHistoryRedisConsumerHandler struct {
} }
func NewOnlineHistoryRedisConsumerHandler( func NewOnlineHistoryRedisConsumerHandler(
config *config.GlobalConfig,
database controller.CommonMsgDatabase, database controller.CommonMsgDatabase,
conversationRpcClient *rpcclient.ConversationRpcClient, conversationRpcClient *rpcclient.ConversationRpcClient,
groupRpcClient *rpcclient.GroupRpcClient, groupRpcClient *rpcclient.GroupRpcClient,
@ -100,79 +97,86 @@ func NewOnlineHistoryRedisConsumerHandler(
och.conversationRpcClient = conversationRpcClient och.conversationRpcClient = conversationRpcClient
och.groupRpcClient = groupRpcClient och.groupRpcClient = groupRpcClient
var err error 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{ och.historyConsumerGroup, err = kafka.NewMConsumerGroup(&kafka.MConsumerGroupConfig{
KafkaVersion: sarama.V2_0_0_0, KafkaVersion: sarama.V2_0_0_0,
OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, OffsetsInitial: sarama.OffsetNewest,
}, []string{config.Config.Kafka.LatestMsgToRedis.Topic}, IsReturnErr: false,
config.Config.Kafka.Addr, config.Config.Kafka.ConsumerGroupID.MsgToRedis) 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 // statistics.NewStatistics(&och.singleMsgSuccessCount, config.Config.ModuleName.MsgTransferName, fmt.Sprintf("%d
// second singleMsgCount insert to mongo", constant.StatisticsTimeInterval), constant.StatisticsTimeInterval) // second singleMsgCount insert to mongo", constant.StatisticsTimeInterval), constant.StatisticsTimeInterval)
return &och, err return &och, err
} }
func (och *OnlineHistoryRedisConsumerHandler) Run(channelID int) { func (och *OnlineHistoryRedisConsumerHandler) Run(channelID int) {
for { for cmd := range och.chArrays[channelID] {
select { switch cmd.Cmd {
case cmd := <-och.chArrays[channelID]: case SourceMessages:
switch cmd.Cmd { msgChannelValue := cmd.Value.(MsgChannelValue)
case SourceMessages: ctxMsgList := msgChannelValue.ctxMsgList
msgChannelValue := cmd.Value.(MsgChannelValue) ctx := msgChannelValue.ctx
ctxMsgList := msgChannelValue.ctxMsgList log.ZDebug(
ctx := msgChannelValue.ctx ctx,
log.ZDebug( "msg arrived channel",
ctx, "channel id",
"msg arrived channel", channelID,
"channel id", "msgList length",
channelID, len(ctxMsgList),
"msgList length", "uniqueKey",
len(ctxMsgList), msgChannelValue.uniqueKey,
"uniqueKey", )
msgChannelValue.uniqueKey, storageMsgList, notStorageMsgList, storageNotificationList, notStorageNotificationList, modifyMsgList := och.getPushStorageMsgList(
) ctxMsgList,
storageMsgList, notStorageMsgList, storageNotificationList, notStorageNotificationList, modifyMsgList := och.getPushStorageMsgList( )
ctxMsgList, log.ZDebug(
) ctx,
log.ZDebug( "msg lens",
ctx, "storageMsgList",
"msg lens", len(storageMsgList),
"storageMsgList", "notStorageMsgList",
len(storageMsgList), len(notStorageMsgList),
"notStorageMsgList", "storageNotificationList",
len(notStorageMsgList), len(storageNotificationList),
"storageNotificationList", "notStorageNotificationList",
len(storageNotificationList), len(notStorageNotificationList),
"notStorageNotificationList", "modifyMsgList",
len(notStorageNotificationList), len(modifyMsgList),
"modifyMsgList", )
len(modifyMsgList), conversationIDMsg := msgprocessor.GetChatConversationIDByMsg(ctxMsgList[0].message)
) conversationIDNotification := msgprocessor.GetNotificationConversationIDByMsg(ctxMsgList[0].message)
conversationIDMsg := msgprocessor.GetChatConversationIDByMsg(ctxMsgList[0].message) och.handleMsg(ctx, msgChannelValue.uniqueKey, conversationIDMsg, storageMsgList, notStorageMsgList)
conversationIDNotification := msgprocessor.GetNotificationConversationIDByMsg(ctxMsgList[0].message) och.handleNotification(
och.handleMsg(ctx, msgChannelValue.uniqueKey, conversationIDMsg, storageMsgList, notStorageMsgList) ctx,
och.handleNotification( msgChannelValue.uniqueKey,
ctx, conversationIDNotification,
msgChannelValue.uniqueKey, storageNotificationList,
conversationIDNotification, notStorageNotificationList,
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)
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( func (och *OnlineHistoryRedisConsumerHandler) getPushStorageMsgList(
totalMsgs []*ContextMsg, totalMsgs []*ContextMsg,
) (storageMsgList, notStorageMsgList, storageNotificatoinList, notStorageNotificationList, modifyMsgList []*sdkws.MsgData) { ) (storageMsgList, notStorageMsgList, storageNotificatoinList, notStorageNotificationList, modifyMsgList []*sdkws.MsgData) {
@ -193,7 +197,7 @@ func (och *OnlineHistoryRedisConsumerHandler) getPushStorageMsgList(
// clone msg from notificationMsg // clone msg from notificationMsg
if options.IsSendMsg() { if options.IsSendMsg() {
msg := proto.Clone(v.message).(*sdkws.MsgData) msg := proto.Clone(v.message).(*sdkws.MsgData)
// 消息 // message
if v.message.Options != nil { if v.message.Options != nil {
msg.Options = msgprocessor.NewMsgOptions() msg.Options = msgprocessor.NewMsgOptions()
} }
@ -268,7 +272,8 @@ func (och *OnlineHistoryRedisConsumerHandler) toPushTopic(
msgs []*sdkws.MsgData, msgs []*sdkws.MsgData,
) { ) {
for _, v := range msgs { 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{} wg = sync.WaitGroup{}
running = new(atomic.Bool) running = new(atomic.Bool)
) )
running.Store(true)
wg.Add(1) wg.Add(1)
go func() { go func() {

@ -18,15 +18,13 @@ import (
"context" "context"
"github.com/IBM/sarama" "github.com/IBM/sarama"
"google.golang.org/protobuf/proto"
pbmsg "github.com/OpenIMSDK/protocol/msg" pbmsg "github.com/OpenIMSDK/protocol/msg"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
kfk "github.com/openimsdk/open-im-server/v3/pkg/common/kafka" kfk "github.com/openimsdk/open-im-server/v3/pkg/common/kafka"
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
"google.golang.org/protobuf/proto"
) )
type OnlineHistoryMongoConsumerHandler struct { type OnlineHistoryMongoConsumerHandler struct {
@ -34,12 +32,28 @@ type OnlineHistoryMongoConsumerHandler struct {
msgDatabase controller.CommonMsgDatabase 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{ historyConsumerGroup, err := kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{
KafkaVersion: sarama.V2_0_0_0, KafkaVersion: sarama.V2_0_0_0,
OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, OffsetsInitial: sarama.OffsetNewest,
}, []string{config.Config.Kafka.MsgToMongo.Topic}, IsReturnErr: false,
config.Config.Kafka.Addr, config.Config.Kafka.ConsumerGroupID.MsgToMongo) UserName: config.Kafka.Username,
Password: config.Kafka.Password,
}, []string{config.Kafka.MsgToMongo.Topic},
config.Kafka.Addr,
config.Kafka.ConsumerGroupID.MsgToMongo,
tlsConfig,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -21,23 +21,19 @@ import (
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/http" "github.com/openimsdk/open-im-server/v3/pkg/common/http"
) )
func url() string {
return config.Config.Callback.CallbackUrl
}
func callbackOfflinePush( func callbackOfflinePush(
ctx context.Context, ctx context.Context,
config *config.GlobalConfig,
userIDs []string, userIDs []string,
msg *sdkws.MsgData, msg *sdkws.MsgData,
offlinePushUserIDs *[]string, offlinePushUserIDs *[]string,
) error { ) error {
if !config.Config.Callback.CallbackOfflinePush.Enable || msg.ContentType == constant.Typing { if !config.Callback.CallbackOfflinePush.Enable || msg.ContentType == constant.Typing {
return nil return nil
} }
req := &callbackstruct.CallbackBeforePushReq{ req := &callbackstruct.CallbackBeforePushReq{
@ -59,10 +55,12 @@ func callbackOfflinePush(
AtUserIDs: msg.AtUserIDList, AtUserIDs: msg.AtUserIDList,
Content: GetContent(msg), Content: GetContent(msg),
} }
resp := &callbackstruct.CallbackBeforePushResp{} resp := &callbackstruct.CallbackBeforePushResp{}
if err := http.CallBackPostReturn(ctx, url(), req, resp, config.Config.Callback.CallbackOfflinePush); err != nil { if err := http.CallBackPostReturn(ctx, config.Callback.CallbackUrl, req, resp, config.Callback.CallbackOfflinePush); err != nil {
return err return err
} }
if len(resp.UserIDs) != 0 { if len(resp.UserIDs) != 0 {
*offlinePushUserIDs = resp.UserIDs *offlinePushUserIDs = resp.UserIDs
} }
@ -72,8 +70,8 @@ func callbackOfflinePush(
return nil return nil
} }
func callbackOnlinePush(ctx context.Context, userIDs []string, msg *sdkws.MsgData) error { func callbackOnlinePush(ctx context.Context, config *config.GlobalConfig, userIDs []string, msg *sdkws.MsgData) error {
if !config.Config.Callback.CallbackOnlinePush.Enable || utils.Contain(msg.SendID, userIDs...) || msg.ContentType == constant.Typing { if !config.Callback.CallbackOnlinePush.Enable || utils.Contain(msg.SendID, userIDs...) || msg.ContentType == constant.Typing {
return nil return nil
} }
req := callbackstruct.CallbackBeforePushReq{ req := callbackstruct.CallbackBeforePushReq{
@ -95,7 +93,7 @@ func callbackOnlinePush(ctx context.Context, userIDs []string, msg *sdkws.MsgDat
Content: GetContent(msg), Content: GetContent(msg),
} }
resp := &callbackstruct.CallbackBeforePushResp{} resp := &callbackstruct.CallbackBeforePushResp{}
if err := http.CallBackPostReturn(ctx, url(), req, resp, config.Config.Callback.CallbackOnlinePush); err != nil { if err := http.CallBackPostReturn(ctx, config.Callback.CallbackUrl, req, resp, config.Callback.CallbackOnlinePush); err != nil {
return err return err
} }
return nil return nil
@ -103,11 +101,12 @@ func callbackOnlinePush(ctx context.Context, userIDs []string, msg *sdkws.MsgDat
func callbackBeforeSuperGroupOnlinePush( func callbackBeforeSuperGroupOnlinePush(
ctx context.Context, ctx context.Context,
config *config.GlobalConfig,
groupID string, groupID string,
msg *sdkws.MsgData, msg *sdkws.MsgData,
pushToUserIDs *[]string, pushToUserIDs *[]string,
) error { ) error {
if !config.Config.Callback.CallbackBeforeSuperGroupOnlinePush.Enable || msg.ContentType == constant.Typing { if !config.Callback.CallbackBeforeSuperGroupOnlinePush.Enable || msg.ContentType == constant.Typing {
return nil return nil
} }
req := callbackstruct.CallbackBeforeSuperGroupOnlinePushReq{ req := callbackstruct.CallbackBeforeSuperGroupOnlinePushReq{
@ -127,7 +126,7 @@ func callbackBeforeSuperGroupOnlinePush(
Seq: msg.Seq, Seq: msg.Seq,
} }
resp := &callbackstruct.CallbackBeforeSuperGroupOnlinePushResp{} resp := &callbackstruct.CallbackBeforeSuperGroupOnlinePushResp{}
if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, req, resp, config.Config.Callback.CallbackBeforeSuperGroupOnlinePush); err != nil { if err := http.CallBackPostReturn(ctx, config.Callback.CallbackUrl, req, resp, config.Callback.CallbackBeforeSuperGroupOnlinePush); err != nil {
return err return err
} }

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

@ -20,14 +20,12 @@ import (
firebase "firebase.google.com/go" firebase "firebase.google.com/go"
"firebase.google.com/go/messaging" "firebase.google.com/go/messaging"
"github.com/redis/go-redis/v9"
"google.golang.org/api/option"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush" "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/redis/go-redis/v9"
"google.golang.org/api/option"
) )
const SinglePushCountLimit = 400 const SinglePushCountLimit = 400
@ -39,20 +37,22 @@ type Fcm struct {
cache cache.MsgModel 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() 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) opt := option.WithCredentialsFile(credentialsFilePath)
fcmApp, err := firebase.NewApp(context.Background(), nil, opt) fcmApp, err := firebase.NewApp(context.Background(), nil, opt)
if err != nil { if err != nil {
return nil return nil
} }
ctx := context.Background() ctx := context.Background()
fcmMsgClient, err := fcmApp.Messaging(ctx) fcmMsgClient, err := fcmApp.Messaging(ctx)
if err != nil { if err != nil {
return nil return nil
} }
return &Fcm{fcmMsgCli: fcmMsgClient, cache: cache} 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) response, err := f.fcmMsgCli.SendAll(ctx, messages)
if err != nil { if err != nil {
Fail = Fail + messageCount Fail = Fail + messageCount
// log.Info(operationID, "some token push err", err.Error(), messageCount)
} else { } else {
Success = Success + response.SuccessCount Success = Success + response.SuccessCount
Fail = Fail + response.FailureCount Fail = Fail + response.FailureCount

@ -133,13 +133,13 @@ type Payload struct {
IsSignal bool `json:"isSignal"` 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{ pushReq := PushReq{PushMessage: &PushMessage{Notification: &Notification{
Title: title, Title: title,
Body: content, Body: content,
ClickType: "startapp", ClickType: "startapp",
ChannelID: config.Config.Push.GeTui.ChannelID, ChannelID: config.Push.GeTui.ChannelID,
ChannelName: config.Config.Push.GeTui.ChannelName, ChannelName: config.Push.GeTui.ChannelName,
}}} }}}
return pushReq return pushReq
} }

@ -23,19 +23,15 @@ import (
"sync" "sync"
"time" "time"
"github.com/redis/go-redis/v9"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils/splitter" "github.com/OpenIMSDK/tools/utils/splitter"
"github.com/openimsdk/open-im-server/v3/internal/push/offlinepush" "github.com/openimsdk/open-im-server/v3/internal/push/offlinepush"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
http2 "github.com/openimsdk/open-im-server/v3/pkg/common/http" http2 "github.com/openimsdk/open-im-server/v3/pkg/common/http"
"github.com/redis/go-redis/v9"
"github.com/OpenIMSDK/tools/utils"
) )
var ( var (
@ -59,10 +55,15 @@ type Client struct {
cache cache.MsgModel cache cache.MsgModel
tokenExpireTime int64 tokenExpireTime int64
taskIDTTL int64 taskIDTTL int64
config *config.GlobalConfig
} }
func NewClient(cache cache.MsgModel) *Client { func NewClient(config *config.GlobalConfig, cache cache.MsgModel) *Client {
return &Client{cache: cache, tokenExpireTime: tokenExpireTime, taskIDTTL: taskIDTTL} 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 { 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 return err
} }
} }
pushReq := newPushReq(title, content) pushReq := newPushReq(g.config, title, content)
pushReq.setPushChannel(title, content) pushReq.setPushChannel(title, content)
if len(userIDs) > 1 { if len(userIDs) > 1 {
maxNum := 999 maxNum := 999
@ -89,9 +90,9 @@ func (g *Client) Push(ctx context.Context, userIDs []string, title, content stri
for i, v := range s.GetSplitResult() { for i, v := range s.GetSplitResult() {
go func(index int, userIDs []string) { go func(index int, userIDs []string) {
defer wg.Done() defer wg.Done()
if err2 := g.batchPush(ctx, token, userIDs, pushReq); err2 != nil { if err := g.batchPush(ctx, token, userIDs, pushReq); err != nil {
log.ZError(ctx, "batchPush failed", err2, "index", index, "token", token, "req", pushReq) log.ZError(ctx, "batchPush failed", err, "index", index, "token", token, "req", pushReq)
err = err2 err = err
} }
}(i, v.Item) }(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) { func (g *Client) Auth(ctx context.Context, timeStamp int64) (token string, expireTime int64, err error) {
h := sha256.New() h := sha256.New()
h.Write( h.Write(
[]byte(config.Config.Push.GeTui.AppKey + strconv.Itoa(int(timeStamp)) + config.Config.Push.GeTui.MasterSecret), []byte(g.config.Push.GeTui.AppKey + strconv.Itoa(int(timeStamp)) + g.config.Push.GeTui.MasterSecret),
) )
sign := hex.EncodeToString(h.Sum(nil)) sign := hex.EncodeToString(h.Sum(nil))
reqAuth := AuthReq{ reqAuth := AuthReq{
Sign: sign, Sign: sign,
Timestamp: strconv.Itoa(int(timeStamp)), Timestamp: strconv.Itoa(int(timeStamp)),
AppKey: config.Config.Push.GeTui.AppKey, AppKey: g.config.Push.GeTui.AppKey,
} }
respAuth := AuthResp{} respAuth := AuthResp{}
err = g.request(ctx, authURL, reqAuth, "", &respAuth) 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} pushReq.Settings = &Settings{TTL: &ttl}
err := g.request(ctx, taskURL, pushReq, token, &respTask) err := g.request(ctx, taskURL, pushReq, token, &respTask)
if err != nil { if err != nil {
return "", utils.Wrap(err, "") return "", errs.Wrap(err)
} }
return respTask.TaskID, nil 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} header := map[string]string{"token": token}
resp := &Resp{} resp := &Resp{}
resp.Data = output resp.Data = output
return g.postReturn(ctx, config.Config.Push.GeTui.PushUrl+url, header, input, resp, 3) return g.postReturn(ctx, g.config.Push.GeTui.PushUrl+url, header, input, resp, 3)
} }
func (g *Client) postReturn( func (g *Client) postReturn(

@ -46,7 +46,6 @@ type Extras struct {
func (n *Notification) SetAlert(alert string) { func (n *Notification) SetAlert(alert string) {
n.Alert = alert n.Alert = alert
n.Android.Alert = alert n.Android.Alert = alert
n.SetAndroidIntent()
n.IOS.Alert = alert n.IOS.Alert = alert
n.IOS.Sound = "default" n.IOS.Sound = "default"
n.IOS.Badge = "+1" n.IOS.Badge = "+1"
@ -57,8 +56,8 @@ func (n *Notification) SetExtras(extras Extras) {
n.Android.Extras = extras n.Android.Extras = extras
} }
func (n *Notification) SetAndroidIntent() { func (n *Notification) SetAndroidIntent(config *config.GlobalConfig) {
n.Android.Intent.URL = config.Config.Push.Jpns.PushIntent n.Android.Intent.URL = config.Push.Jpns.PushIntent
} }
func (n *Notification) IOSEnableMutableContent() { func (n *Notification) IOSEnableMutableContent() {

@ -25,10 +25,12 @@ import (
http2 "github.com/openimsdk/open-im-server/v3/pkg/common/http" http2 "github.com/openimsdk/open-im-server/v3/pkg/common/http"
) )
type JPush struct{} type JPush struct {
config *config.GlobalConfig
}
func NewClient() *JPush { func NewClient(config *config.GlobalConfig) *JPush {
return &JPush{} return &JPush{config: config}
} }
func (j *JPush) Auth(apiKey, secretKey string, timeStamp int64) (token string, err error) { 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.IOSEnableMutableContent()
no.SetExtras(extras) no.SetExtras(extras)
no.SetAlert(title) no.SetAlert(title)
no.SetAndroidIntent(j.config)
var msg body.Message var msg body.Message
msg.SetMsgContent(content) msg.SetMsgContent(content)
var opt body.Options var opt body.Options
opt.SetApnsProduction(config.Config.IOSPush.Production) opt.SetApnsProduction(j.config.IOSPush.Production)
var pushObj body.PushObj var pushObj body.PushObj
pushObj.SetPlatform(&pf) pushObj.SetPlatform(&pf)
pushObj.SetAudience(&au) 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 { func (j *JPush) request(ctx context.Context, po body.PushObj, resp any, timeout int) error {
return http2.PostReturn( return http2.PostReturn(
ctx, ctx,
config.Config.Push.Jpns.PushUrl, j.config.Push.Jpns.PushUrl,
map[string]string{ 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, po,
resp, resp,

@ -18,16 +18,14 @@ import (
"context" "context"
"github.com/IBM/sarama" "github.com/IBM/sarama"
"google.golang.org/protobuf/proto"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
pbchat "github.com/OpenIMSDK/protocol/msg" pbchat "github.com/OpenIMSDK/protocol/msg"
pbpush "github.com/OpenIMSDK/protocol/push" pbpush "github.com/OpenIMSDK/protocol/push"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
kfk "github.com/openimsdk/open-im-server/v3/pkg/common/kafka" kfk "github.com/openimsdk/open-im-server/v3/pkg/common/kafka"
"google.golang.org/protobuf/proto"
) )
type ConsumerHandler struct { type ConsumerHandler struct {
@ -35,15 +33,29 @@ type ConsumerHandler struct {
pusher *Pusher pusher *Pusher
} }
func NewConsumerHandler(pusher *Pusher) (*ConsumerHandler, error) { func NewConsumerHandler(config *config.GlobalConfig, pusher *Pusher) (*ConsumerHandler, error) {
var consumerHandler ConsumerHandler var consumerHandler ConsumerHandler
consumerHandler.pusher = pusher consumerHandler.pusher = pusher
var err error 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{ consumerHandler.pushConsumerGroup, err = kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{
KafkaVersion: sarama.V2_0_0_0, KafkaVersion: sarama.V2_0_0_0,
OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false, OffsetsInitial: sarama.OffsetNewest,
}, []string{config.Config.Kafka.MsgToPush.Topic}, config.Config.Kafka.Addr, IsReturnErr: false,
config.Config.Kafka.ConsumerGroupID.MsgToPush) UserName: config.Kafka.Username,
Password: config.Kafka.Password,
}, []string{config.Kafka.MsgToPush.Topic}, config.Kafka.Addr,
config.Kafka.ConsumerGroupID.MsgToPush,
tlsConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }

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

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

@ -17,10 +17,6 @@ package auth
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
"google.golang.org/grpc"
pbauth "github.com/OpenIMSDK/protocol/auth" pbauth "github.com/OpenIMSDK/protocol/auth"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/msggateway" "github.com/OpenIMSDK/protocol/msggateway"
@ -29,42 +25,45 @@ import (
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/tokenverify" "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/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics" "github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"google.golang.org/grpc"
) )
type authServer struct { type authServer struct {
authDatabase controller.AuthDatabase authDatabase controller.AuthDatabase
userRpcClient *rpcclient.UserRpcClient userRpcClient *rpcclient.UserRpcClient
RegisterCenter discoveryregistry.SvcDiscoveryRegistry RegisterCenter discoveryregistry.SvcDiscoveryRegistry
config *config.GlobalConfig
} }
func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
rdb, err := cache.NewRedis() rdb, err := cache.NewRedis(config)
if err != nil { if err != nil {
return err return err
} }
userRpcClient := rpcclient.NewUserRpcClient(client) userRpcClient := rpcclient.NewUserRpcClient(client, config)
pbauth.RegisterAuthServer(server, &authServer{ pbauth.RegisterAuthServer(server, &authServer{
userRpcClient: &userRpcClient, userRpcClient: &userRpcClient,
RegisterCenter: client, RegisterCenter: client,
authDatabase: controller.NewAuthDatabase( authDatabase: controller.NewAuthDatabase(
cache.NewMsgCacheModel(rdb), cache.NewMsgCacheModel(rdb, config),
config.Config.Secret, config.Secret,
config.Config.TokenPolicy.Expire, config.TokenPolicy.Expire,
config,
), ),
config: config,
}) })
return nil return nil
} }
func (s *authServer) UserToken(ctx context.Context, req *pbauth.UserTokenReq) (*pbauth.UserTokenResp, error) { func (s *authServer) UserToken(ctx context.Context, req *pbauth.UserTokenReq) (*pbauth.UserTokenResp, error) {
resp := pbauth.UserTokenResp{} resp := pbauth.UserTokenResp{}
if req.Secret != config.Config.Secret { if req.Secret != s.config.Secret {
return nil, errs.ErrNoPermission.Wrap("secret invalid") return nil, errs.ErrNoPermission.Wrap("secret invalid")
} }
if _, err := s.userRpcClient.GetUserInfo(ctx, req.UserID); err != nil { 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() prommetrics.UserLoginCounter.Inc()
resp.Token = token resp.Token = token
resp.ExpireTimeSeconds = config.Config.TokenPolicy.Expire * 24 * 60 * 60 resp.ExpireTimeSeconds = s.config.TokenPolicy.Expire * 24 * 60 * 60
return &resp, nil return &resp, nil
} }
func (s *authServer) GetUserToken(ctx context.Context, req *pbauth.GetUserTokenReq) (*pbauth.GetUserTokenResp, error) { 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 return nil, err
} }
resp := pbauth.GetUserTokenResp{} 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") 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 return nil, err
} }
resp.Token = token resp.Token = token
resp.ExpireTimeSeconds = config.Config.TokenPolicy.Expire * 24 * 60 * 60 resp.ExpireTimeSeconds = s.config.TokenPolicy.Expire * 24 * 60 * 60
return &resp, nil return &resp, nil
} }
func (s *authServer) parseToken(ctx context.Context, tokensString string) (claims *tokenverify.Claims, err error) { 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 { if err != nil {
return nil, utils.Wrap(err, "") return nil, errs.Wrap(err)
} }
m, err := s.authDatabase.GetTokensWithoutError(ctx, claims.UserID, claims.PlatformID) m, err := s.authDatabase.GetTokensWithoutError(ctx, claims.UserID, claims.PlatformID)
if err != nil { if err != nil {
@ -121,7 +120,7 @@ func (s *authServer) parseToken(ctx context.Context, tokensString string) (claim
case constant.KickedToken: case constant.KickedToken:
return nil, errs.ErrTokenKicked.Wrap() return nil, errs.ErrTokenKicked.Wrap()
default: default:
return nil, utils.Wrap(errs.ErrTokenUnknown, "") return nil, errs.Wrap(errs.ErrTokenUnknown)
} }
} }
return nil, errs.ErrTokenNotExist.Wrap() 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) { 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 return nil, err
} }
if err := s.forceKickOff(ctx, req.UserID, req.PlatformID, mcontext.GetOperationID(ctx)); err != nil { 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 { 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 { if err != nil {
return err return err
} }

@ -19,28 +19,24 @@ import (
"errors" "errors"
"sort" "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" "github.com/OpenIMSDK/protocol/constant"
pbconversation "github.com/OpenIMSDK/protocol/conversation" pbconversation "github.com/OpenIMSDK/protocol/conversation"
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/convert"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
"google.golang.org/grpc"
) )
type conversationServer struct { type conversationServer struct {
@ -49,6 +45,7 @@ type conversationServer struct {
groupRpcClient *rpcclient.GroupRpcClient groupRpcClient *rpcclient.GroupRpcClient
conversationDatabase controller.ConversationDatabase conversationDatabase controller.ConversationDatabase
conversationNotificationSender *notification.ConversationNotificationSender conversationNotificationSender *notification.ConversationNotificationSender
config *config.GlobalConfig
} }
func (c *conversationServer) GetConversationNotReceiveMessageUserIDs( func (c *conversationServer) GetConversationNotReceiveMessageUserIDs(
@ -59,28 +56,29 @@ func (c *conversationServer) GetConversationNotReceiveMessageUserIDs(
panic("implement me") panic("implement me")
} }
func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
rdb, err := cache.NewRedis() rdb, err := cache.NewRedis(config)
if err != nil { if err != nil {
return err return err
} }
mongo, err := unrelation.NewMongo() mongo, err := unrelation.NewMongo(config)
if err != nil { if err != nil {
return err return err
} }
conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase()) conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase(config.Mongo.Database))
if err != nil { if err != nil {
return err return err
} }
groupRpcClient := rpcclient.NewGroupRpcClient(client) groupRpcClient := rpcclient.NewGroupRpcClient(client, config)
msgRpcClient := rpcclient.NewMessageRpcClient(client) msgRpcClient := rpcclient.NewMessageRpcClient(client, config)
userRpcClient := rpcclient.NewUserRpcClient(client) userRpcClient := rpcclient.NewUserRpcClient(client, config)
pbconversation.RegisterConversationServer(server, &conversationServer{ pbconversation.RegisterConversationServer(server, &conversationServer{
msgRpcClient: &msgRpcClient, msgRpcClient: &msgRpcClient,
user: &userRpcClient, user: &userRpcClient,
conversationNotificationSender: notification.NewConversationNotificationSender(&msgRpcClient), conversationNotificationSender: notification.NewConversationNotificationSender(config, &msgRpcClient),
groupRpcClient: &groupRpcClient, groupRpcClient: &groupRpcClient,
conversationDatabase: controller.NewConversationDatabase(conversationDB, cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB), tx.NewMongo(mongo.GetClient())), conversationDatabase: controller.NewConversationDatabase(conversationDB, cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB), tx.NewMongo(mongo.GetClient())),
config: config,
}) })
return nil return nil
} }
@ -310,7 +308,7 @@ func (c *conversationServer) SetConversations(ctx context.Context,
unequal++ 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 return nil, err
} }
if unequal > 0 { if unequal > 0 {
@ -321,7 +319,7 @@ func (c *conversationServer) SetConversations(ctx context.Context,
return &pbconversation.SetConversationsResp{}, nil 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) { func (c *conversationServer) GetRecvMsgNotNotifyUserIDs(ctx context.Context, req *pbconversation.GetRecvMsgNotNotifyUserIDsReq) (*pbconversation.GetRecvMsgNotNotifyUserIDsResp, error) {
//userIDs, err := c.conversationDatabase.FindRecvMsgNotNotifyUserIDs(ctx, req.GroupID) //userIDs, err := c.conversationDatabase.FindRecvMsgNotNotifyUserIDs(ctx, req.GroupID)
//if err != nil { //if err != nil {
@ -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) { 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 { map[string]any{"max_seq": req.MaxSeq}); err != nil {
return nil, err return nil, err
} }

@ -18,11 +18,9 @@ import (
"context" "context"
"time" "time"
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
pbfriend "github.com/OpenIMSDK/protocol/friend" pbfriend "github.com/OpenIMSDK/protocol/friend"
"github.com/OpenIMSDK/tools/mcontext" "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/convert"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "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) { 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 return nil, err
} }
_, err := s.userRpcClient.GetUsersInfo(ctx, []string{req.OwnerUserID, req.BlackUserID}) _, err := s.userRpcClient.GetUsersInfo(ctx, []string{req.OwnerUserID, req.BlackUserID})

@ -19,14 +19,13 @@ import (
pbfriend "github.com/OpenIMSDK/protocol/friend" pbfriend "github.com/OpenIMSDK/protocol/friend"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/http" "github.com/openimsdk/open-im-server/v3/pkg/common/http"
) )
func CallbackBeforeAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) error { func CallbackBeforeAddFriend(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.ApplyToAddFriendReq) error {
if !config.Config.Callback.CallbackBeforeAddFriend.Enable { if !globalConfig.Callback.CallbackBeforeAddFriend.Enable {
return nil return nil
} }
cbReq := &cbapi.CallbackBeforeAddFriendReq{ cbReq := &cbapi.CallbackBeforeAddFriendReq{
@ -37,14 +36,14 @@ func CallbackBeforeAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriend
Ex: req.Ex, Ex: req.Ex,
} }
resp := &cbapi.CallbackBeforeAddFriendResp{} resp := &cbapi.CallbackBeforeAddFriendResp{}
if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeAddFriend); err != nil { if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeAddFriend); err != nil {
return err return err
} }
return nil return nil
} }
func CallbackBeforeSetFriendRemark(ctx context.Context, req *pbfriend.SetFriendRemarkReq) error { func CallbackBeforeSetFriendRemark(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.SetFriendRemarkReq) error {
if !config.Config.Callback.CallbackBeforeSetFriendRemark.Enable { if !globalConfig.Callback.CallbackBeforeSetFriendRemark.Enable {
return nil return nil
} }
cbReq := &cbapi.CallbackBeforeSetFriendRemarkReq{ cbReq := &cbapi.CallbackBeforeSetFriendRemarkReq{
@ -54,15 +53,15 @@ func CallbackBeforeSetFriendRemark(ctx context.Context, req *pbfriend.SetFriendR
Remark: req.Remark, Remark: req.Remark,
} }
resp := &cbapi.CallbackBeforeSetFriendRemarkResp{} 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 return err
} }
utils.NotNilReplace(&req.Remark, &resp.Remark) utils.NotNilReplace(&req.Remark, &resp.Remark)
return nil return nil
} }
func CallbackAfterSetFriendRemark(ctx context.Context, req *pbfriend.SetFriendRemarkReq) error { func CallbackAfterSetFriendRemark(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.SetFriendRemarkReq) error {
if !config.Config.Callback.CallbackAfterSetFriendRemark.Enable { if !globalConfig.Callback.CallbackAfterSetFriendRemark.Enable {
return nil return nil
} }
cbReq := &cbapi.CallbackAfterSetFriendRemarkReq{ cbReq := &cbapi.CallbackAfterSetFriendRemarkReq{
@ -72,13 +71,13 @@ func CallbackAfterSetFriendRemark(ctx context.Context, req *pbfriend.SetFriendRe
Remark: req.Remark, Remark: req.Remark,
} }
resp := &cbapi.CallbackAfterSetFriendRemarkResp{} 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 err
} }
return nil return nil
} }
func CallbackBeforeAddBlack(ctx context.Context, req *pbfriend.AddBlackReq) error { func CallbackBeforeAddBlack(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.AddBlackReq) error {
if !config.Config.Callback.CallbackBeforeAddBlack.Enable { if !globalConfig.Callback.CallbackBeforeAddBlack.Enable {
return nil return nil
} }
cbReq := &cbapi.CallbackBeforeAddBlackReq{ cbReq := &cbapi.CallbackBeforeAddBlackReq{
@ -87,13 +86,13 @@ func CallbackBeforeAddBlack(ctx context.Context, req *pbfriend.AddBlackReq) erro
BlackUserID: req.BlackUserID, BlackUserID: req.BlackUserID,
} }
resp := &cbapi.CallbackBeforeAddBlackResp{} 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 err
} }
return nil return nil
} }
func CallbackAfterAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) error { func CallbackAfterAddFriend(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.ApplyToAddFriendReq) error {
if !config.Config.Callback.CallbackAfterAddFriend.Enable { if !globalConfig.Callback.CallbackAfterAddFriend.Enable {
return nil return nil
} }
cbReq := &cbapi.CallbackAfterAddFriendReq{ cbReq := &cbapi.CallbackAfterAddFriendReq{
@ -103,14 +102,14 @@ func CallbackAfterAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendR
ReqMsg: req.ReqMsg, ReqMsg: req.ReqMsg,
} }
resp := &cbapi.CallbackAfterAddFriendResp{} 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 err
} }
return nil return nil
} }
func CallbackBeforeAddFriendAgree(ctx context.Context, req *pbfriend.RespondFriendApplyReq) error { func CallbackBeforeAddFriendAgree(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.RespondFriendApplyReq) error {
if !config.Config.Callback.CallbackBeforeAddFriendAgree.Enable { if !globalConfig.Callback.CallbackBeforeAddFriendAgree.Enable {
return nil return nil
} }
cbReq := &cbapi.CallbackBeforeAddFriendAgreeReq{ cbReq := &cbapi.CallbackBeforeAddFriendAgreeReq{
@ -121,13 +120,13 @@ func CallbackBeforeAddFriendAgree(ctx context.Context, req *pbfriend.RespondFrie
HandleResult: req.HandleResult, HandleResult: req.HandleResult,
} }
resp := &cbapi.CallbackBeforeAddFriendAgreeResp{} 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 err
} }
return nil return nil
} }
func CallbackAfterDeleteFriend(ctx context.Context, req *pbfriend.DeleteFriendReq) error { func CallbackAfterDeleteFriend(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.DeleteFriendReq) error {
if !config.Config.Callback.CallbackAfterDeleteFriend.Enable { if !globalConfig.Callback.CallbackAfterDeleteFriend.Enable {
return nil return nil
} }
cbReq := &cbapi.CallbackAfterDeleteFriendReq{ cbReq := &cbapi.CallbackAfterDeleteFriendReq{
@ -136,13 +135,13 @@ func CallbackAfterDeleteFriend(ctx context.Context, req *pbfriend.DeleteFriendRe
FriendUserID: req.FriendUserID, FriendUserID: req.FriendUserID,
} }
resp := &cbapi.CallbackAfterDeleteFriendResp{} 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 err
} }
return nil return nil
} }
func CallbackBeforeImportFriends(ctx context.Context, req *pbfriend.ImportFriendReq) error { func CallbackBeforeImportFriends(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.ImportFriendReq) error {
if !config.Config.Callback.CallbackBeforeImportFriends.Enable { if !globalConfig.Callback.CallbackBeforeImportFriends.Enable {
return nil return nil
} }
cbReq := &cbapi.CallbackBeforeImportFriendsReq{ cbReq := &cbapi.CallbackBeforeImportFriendsReq{
@ -151,7 +150,7 @@ func CallbackBeforeImportFriends(ctx context.Context, req *pbfriend.ImportFriend
FriendUserIDs: req.FriendUserIDs, FriendUserIDs: req.FriendUserIDs,
} }
resp := &cbapi.CallbackBeforeImportFriendsResp{} 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 return err
} }
if len(resp.FriendUserIDs) != 0 { if len(resp.FriendUserIDs) != 0 {
@ -159,8 +158,8 @@ func CallbackBeforeImportFriends(ctx context.Context, req *pbfriend.ImportFriend
} }
return nil return nil
} }
func CallbackAfterImportFriends(ctx context.Context, req *pbfriend.ImportFriendReq) error { func CallbackAfterImportFriends(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.ImportFriendReq) error {
if !config.Config.Callback.CallbackAfterImportFriends.Enable { if !globalConfig.Callback.CallbackAfterImportFriends.Enable {
return nil return nil
} }
cbReq := &cbapi.CallbackAfterImportFriendsReq{ cbReq := &cbapi.CallbackAfterImportFriendsReq{
@ -169,14 +168,14 @@ func CallbackAfterImportFriends(ctx context.Context, req *pbfriend.ImportFriendR
FriendUserIDs: req.FriendUserIDs, FriendUserIDs: req.FriendUserIDs,
} }
resp := &cbapi.CallbackAfterImportFriendsResp{} 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 err
} }
return nil return nil
} }
func CallbackAfterRemoveBlack(ctx context.Context, req *pbfriend.RemoveBlackReq) error { func CallbackAfterRemoveBlack(ctx context.Context, globalConfig *config.GlobalConfig, req *pbfriend.RemoveBlackReq) error {
if !config.Config.Callback.CallbackAfterRemoveBlack.Enable { if !globalConfig.Callback.CallbackAfterRemoveBlack.Enable {
return nil return nil
} }
cbReq := &cbapi.CallbackAfterRemoveBlackReq{ cbReq := &cbapi.CallbackAfterRemoveBlackReq{
@ -185,7 +184,7 @@ func CallbackAfterRemoveBlack(ctx context.Context, req *pbfriend.RemoveBlackReq)
BlackUserID: req.BlackUserID, BlackUserID: req.BlackUserID,
} }
resp := &cbapi.CallbackAfterRemoveBlackResp{} 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 err
} }
return nil return nil

@ -17,31 +17,25 @@ package friend
import ( import (
"context" "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" "github.com/OpenIMSDK/protocol/constant"
pbfriend "github.com/OpenIMSDK/protocol/friend" pbfriend "github.com/OpenIMSDK/protocol/friend"
"github.com/OpenIMSDK/protocol/sdkws"
registry "github.com/OpenIMSDK/tools/discoveryregistry" registry "github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo" "github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" tablerelation "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
"google.golang.org/grpc"
) )
type friendServer struct { type friendServer struct {
@ -51,42 +45,44 @@ type friendServer struct {
notificationSender *notification.FriendNotificationSender notificationSender *notification.FriendNotificationSender
conversationRpcClient rpcclient.ConversationRpcClient conversationRpcClient rpcclient.ConversationRpcClient
RegisterCenter registry.SvcDiscoveryRegistry 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 // Initialize MongoDB
mongo, err := unrelation.NewMongo() mongo, err := unrelation.NewMongo(config)
if err != nil { if err != nil {
return err return err
} }
// Initialize Redis // Initialize Redis
rdb, err := cache.NewRedis() rdb, err := cache.NewRedis(config)
if err != nil { if err != nil {
return err return err
} }
friendMongoDB, err := mgo.NewFriendMongo(mongo.GetDatabase()) friendMongoDB, err := mgo.NewFriendMongo(mongo.GetDatabase(config.Mongo.Database))
if err != nil { if err != nil {
return err return err
} }
friendRequestMongoDB, err := mgo.NewFriendRequestMongo(mongo.GetDatabase()) friendRequestMongoDB, err := mgo.NewFriendRequestMongo(mongo.GetDatabase(config.Mongo.Database))
if err != nil { if err != nil {
return err return err
} }
blackMongoDB, err := mgo.NewBlackMongo(mongo.GetDatabase()) blackMongoDB, err := mgo.NewBlackMongo(mongo.GetDatabase(config.Mongo.Database))
if err != nil { if err != nil {
return err return err
} }
// Initialize RPC clients // Initialize RPC clients
userRpcClient := rpcclient.NewUserRpcClient(client) userRpcClient := rpcclient.NewUserRpcClient(client, config)
msgRpcClient := rpcclient.NewMessageRpcClient(client) msgRpcClient := rpcclient.NewMessageRpcClient(client, config)
// Initialize notification sender // Initialize notification sender
notificationSender := notification.NewFriendNotificationSender( notificationSender := notification.NewFriendNotificationSender(
config,
&msgRpcClient, &msgRpcClient,
notification.WithRpcFunc(userRpcClient.GetUsersInfo), notification.WithRpcFunc(userRpcClient.GetUsersInfo),
) )
@ -105,7 +101,8 @@ func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error {
userRpcClient: &userRpcClient, userRpcClient: &userRpcClient,
notificationSender: notificationSender, notificationSender: notificationSender,
RegisterCenter: client, RegisterCenter: client,
conversationRpcClient: rpcclient.NewConversationRpcClient(client), conversationRpcClient: rpcclient.NewConversationRpcClient(client, config),
config: config,
}) })
return nil return nil
@ -113,15 +110,14 @@ func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error {
// ok. // ok.
func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) (resp *pbfriend.ApplyToAddFriendResp, err error) { func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.ApplyToAddFriendReq) (resp *pbfriend.ApplyToAddFriendResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
resp = &pbfriend.ApplyToAddFriendResp{} 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 return nil, err
} }
if req.ToUserID == req.FromUserID { 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 return nil, err
} }
if _, err := s.userRpcClient.GetUsersInfoMap(ctx, []string{req.ToUserID, req.FromUserID}); err != nil { if _, err := s.userRpcClient.GetUsersInfoMap(ctx, []string{req.ToUserID, req.FromUserID}); err != nil {
@ -138,7 +134,7 @@ func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.Apply
return nil, err return nil, err
} }
s.notificationSender.FriendApplicationAddNotification(ctx, req) s.notificationSender.FriendApplicationAddNotification(ctx, req)
if err = CallbackAfterAddFriend(ctx, req); err != nil && err != errs.ErrCallbackContinue { if err = CallbackAfterAddFriend(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue {
return nil, err return nil, err
} }
return resp, nil return resp, nil
@ -147,7 +143,7 @@ func (s *friendServer) ApplyToAddFriend(ctx context.Context, req *pbfriend.Apply
// ok. // ok.
func (s *friendServer) ImportFriends(ctx context.Context, req *pbfriend.ImportFriendReq) (resp *pbfriend.ImportFriendResp, err error) { func (s *friendServer) ImportFriends(ctx context.Context, req *pbfriend.ImportFriendReq) (resp *pbfriend.ImportFriendResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
if err := authverify.CheckAdmin(ctx); err != nil { if err := authverify.CheckAdmin(ctx, s.config); err != nil {
return nil, err return nil, err
} }
if _, err := s.userRpcClient.GetUsersInfo(ctx, append([]string{req.OwnerUserID}, req.FriendUserIDs...)); err != nil { 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) { if utils.Duplicate(req.FriendUserIDs) {
return nil, errs.ErrArgs.Wrap("friend userID repeated") return nil, errs.ErrArgs.Wrap("friend userID repeated")
} }
if err := CallbackBeforeImportFriends(ctx, req); err != nil { if err := CallbackBeforeImportFriends(ctx, s.config, req); err != nil {
return nil, err return nil, err
} }
@ -173,7 +169,7 @@ func (s *friendServer) ImportFriends(ctx context.Context, req *pbfriend.ImportFr
HandleResult: constant.FriendResponseAgree, HandleResult: constant.FriendResponseAgree,
}) })
} }
if err := CallbackAfterImportFriends(ctx, req); err != nil { if err := CallbackAfterImportFriends(ctx, s.config, req); err != nil {
return nil, err return nil, err
} }
return &pbfriend.ImportFriendResp{}, nil 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) { func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.RespondFriendApplyReq) (resp *pbfriend.RespondFriendApplyResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
resp = &pbfriend.RespondFriendApplyResp{} resp = &pbfriend.RespondFriendApplyResp{}
if err := authverify.CheckAccessV3(ctx, req.ToUserID); err != nil { if err := authverify.CheckAccessV3(ctx, req.ToUserID, s.config); err != nil {
return nil, err return nil, err
} }
@ -194,7 +190,7 @@ func (s *friendServer) RespondFriendApply(ctx context.Context, req *pbfriend.Res
HandleResult: req.HandleResult, HandleResult: req.HandleResult,
} }
if req.HandleResult == constant.FriendResponseAgree { if req.HandleResult == constant.FriendResponseAgree {
if err := CallbackBeforeAddFriendAgree(ctx, req); err != nil && err != errs.ErrCallbackContinue { if err := CallbackBeforeAddFriendAgree(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue {
return nil, err return nil, err
} }
err := s.friendDatabase.AgreeFriendRequest(ctx, &friendRequest) err := s.friendDatabase.AgreeFriendRequest(ctx, &friendRequest)
@ -230,7 +226,7 @@ func (s *friendServer) DeleteFriend(ctx context.Context, req *pbfriend.DeleteFri
return nil, err return nil, err
} }
s.notificationSender.FriendDeletedNotification(ctx, req) s.notificationSender.FriendDeletedNotification(ctx, req)
if err := CallbackAfterDeleteFriend(ctx, req); err != nil { if err := CallbackAfterDeleteFriend(ctx, s.config, req); err != nil {
return nil, err return nil, err
} }
return resp, nil 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) { func (s *friendServer) SetFriendRemark(ctx context.Context, req *pbfriend.SetFriendRemarkReq) (resp *pbfriend.SetFriendRemarkResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
if err = CallbackBeforeSetFriendRemark(ctx, req); err != nil && err != errs.ErrCallbackContinue { if err = CallbackBeforeSetFriendRemark(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue {
return nil, err return nil, err
} }
resp = &pbfriend.SetFriendRemarkResp{} 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 { if err := s.friendDatabase.UpdateRemark(ctx, req.OwnerUserID, req.FriendUserID, req.Remark); err != nil {
return nil, err return nil, err
} }
if err := CallbackAfterSetFriendRemark(ctx, req); err != nil && err != errs.ErrCallbackContinue { if err := CallbackAfterSetFriendRemark(ctx, s.config, req); err != nil && err != errs.ErrCallbackContinue {
return nil, err return nil, err
} }
s.notificationSender.FriendRemarkSetNotification(ctx, req.OwnerUserID, req.FriendUserID) 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 return resp, nil
} }
// Get the list of friend requests sent out proactively.
func (s *friendServer) GetDesignatedFriendsApply(ctx context.Context, func (s *friendServer) GetDesignatedFriendsApply(ctx context.Context,
req *pbfriend.GetDesignatedFriendsApplyReq) (resp *pbfriend.GetDesignatedFriendsApplyResp, err error) { req *pbfriend.GetDesignatedFriendsApplyReq) (resp *pbfriend.GetDesignatedFriendsApplyResp, err error) {
friendRequests, err := s.friendDatabase.FindBothFriendRequests(ctx, req.FromUserID, req.ToUserID) friendRequests, err := s.friendDatabase.FindBothFriendRequests(ctx, req.FromUserID, req.ToUserID)
@ -292,7 +289,7 @@ func (s *friendServer) GetDesignatedFriendsApply(ctx context.Context,
return resp, nil 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) { func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyToReq) (resp *pbfriend.GetPaginationFriendsApplyToResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
if err := s.userRpcClient.Access(ctx, req.UserID); err != nil { if err := s.userRpcClient.Access(ctx, req.UserID); err != nil {
@ -311,7 +308,6 @@ func (s *friendServer) GetPaginationFriendsApplyTo(ctx context.Context, req *pbf
return resp, nil return resp, nil
} }
// ok 获取主动发出去的好友申请列表.
func (s *friendServer) GetPaginationFriendsApplyFrom(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyFromReq) (resp *pbfriend.GetPaginationFriendsApplyFromResp, err error) { func (s *friendServer) GetPaginationFriendsApplyFrom(ctx context.Context, req *pbfriend.GetPaginationFriendsApplyFromReq) (resp *pbfriend.GetPaginationFriendsApplyFromResp, err error) {
defer log.ZInfo(ctx, utils.GetFuncName()+" Return") defer log.ZInfo(ctx, utils.GetFuncName()+" Return")
resp = &pbfriend.GetPaginationFriendsApplyFromResp{} resp = &pbfriend.GetPaginationFriendsApplyFromResp{}

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

@ -18,16 +18,13 @@ import (
"context" "context"
"time" "time"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/group" "github.com/OpenIMSDK/protocol/group"
pbgroup "github.com/OpenIMSDK/protocol/group"
"github.com/OpenIMSDK/protocol/wrapperspb" "github.com/OpenIMSDK/protocol/wrapperspb"
"github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
pbgroup "github.com/OpenIMSDK/protocol/group"
"github.com/openimsdk/open-im-server/v3/pkg/apistruct" "github.com/openimsdk/open-im-server/v3/pkg/apistruct"
"github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
@ -35,8 +32,8 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/common/http" "github.com/openimsdk/open-im-server/v3/pkg/common/http"
) )
func CallbackBeforeCreateGroup(ctx context.Context, req *group.CreateGroupReq) (err error) { func CallbackBeforeCreateGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *group.CreateGroupReq) (err error) {
if !config.Config.Callback.CallbackBeforeCreateGroup.Enable { if !globalConfig.Callback.CallbackBeforeCreateGroup.Enable {
return nil return nil
} }
cbReq := &callbackstruct.CallbackBeforeCreateGroupReq{ cbReq := &callbackstruct.CallbackBeforeCreateGroupReq{
@ -61,7 +58,7 @@ func CallbackBeforeCreateGroup(ctx context.Context, req *group.CreateGroupReq) (
}) })
} }
resp := &callbackstruct.CallbackBeforeCreateGroupResp{} resp := &callbackstruct.CallbackBeforeCreateGroupResp{}
if err = http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeCreateGroup); err != nil { if err = http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeCreateGroup); err != nil {
return err return err
} }
utils.NotNilReplace(&req.GroupInfo.GroupID, resp.GroupID) utils.NotNilReplace(&req.GroupInfo.GroupID, resp.GroupID)
@ -79,8 +76,8 @@ func CallbackBeforeCreateGroup(ctx context.Context, req *group.CreateGroupReq) (
return nil return nil
} }
func CallbackAfterCreateGroup(ctx context.Context, req *group.CreateGroupReq) (err error) { func CallbackAfterCreateGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *group.CreateGroupReq) (err error) {
if !config.Config.Callback.CallbackAfterCreateGroup.Enable { if !globalConfig.Callback.CallbackAfterCreateGroup.Enable {
return nil return nil
} }
cbReq := &callbackstruct.CallbackAfterCreateGroupReq{ cbReq := &callbackstruct.CallbackAfterCreateGroupReq{
@ -104,7 +101,7 @@ func CallbackAfterCreateGroup(ctx context.Context, req *group.CreateGroupReq) (e
}) })
} }
resp := &callbackstruct.CallbackAfterCreateGroupResp{} 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 err
} }
return nil return nil
@ -112,10 +109,11 @@ func CallbackAfterCreateGroup(ctx context.Context, req *group.CreateGroupReq) (e
func CallbackBeforeMemberJoinGroup( func CallbackBeforeMemberJoinGroup(
ctx context.Context, ctx context.Context,
globalConfig *config.GlobalConfig,
groupMember *relation.GroupMemberModel, groupMember *relation.GroupMemberModel,
groupEx string, groupEx string,
) (err error) { ) (err error) {
if !config.Config.Callback.CallbackBeforeMemberJoinGroup.Enable { if !globalConfig.Callback.CallbackBeforeMemberJoinGroup.Enable {
return nil return nil
} }
callbackReq := &callbackstruct.CallbackBeforeMemberJoinGroupReq{ callbackReq := &callbackstruct.CallbackBeforeMemberJoinGroupReq{
@ -128,10 +126,10 @@ func CallbackBeforeMemberJoinGroup(
resp := &callbackstruct.CallbackBeforeMemberJoinGroupResp{} resp := &callbackstruct.CallbackBeforeMemberJoinGroupResp{}
err = http.CallBackPostReturn( err = http.CallBackPostReturn(
ctx, ctx,
config.Config.Callback.CallbackUrl, globalConfig.Callback.CallbackUrl,
callbackReq, callbackReq,
resp, resp,
config.Config.Callback.CallbackBeforeMemberJoinGroup, globalConfig.Callback.CallbackBeforeMemberJoinGroup,
) )
if err != nil { if err != nil {
return err return err
@ -146,8 +144,8 @@ func CallbackBeforeMemberJoinGroup(
return nil return nil
} }
func CallbackBeforeSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMemberInfo) (err error) { func CallbackBeforeSetGroupMemberInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *group.SetGroupMemberInfo) (err error) {
if !config.Config.Callback.CallbackBeforeSetGroupMemberInfo.Enable { if !globalConfig.Callback.CallbackBeforeSetGroupMemberInfo.Enable {
return nil return nil
} }
callbackReq := callbackstruct.CallbackBeforeSetGroupMemberInfoReq{ callbackReq := callbackstruct.CallbackBeforeSetGroupMemberInfoReq{
@ -170,10 +168,10 @@ func CallbackBeforeSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMe
resp := &callbackstruct.CallbackBeforeSetGroupMemberInfoResp{} resp := &callbackstruct.CallbackBeforeSetGroupMemberInfoResp{}
err = http.CallBackPostReturn( err = http.CallBackPostReturn(
ctx, ctx,
config.Config.Callback.CallbackUrl, globalConfig.Callback.CallbackUrl,
callbackReq, callbackReq,
resp, resp,
config.Config.Callback.CallbackBeforeSetGroupMemberInfo, globalConfig.Callback.CallbackBeforeSetGroupMemberInfo,
) )
if err != nil { if err != nil {
return err return err
@ -192,8 +190,8 @@ func CallbackBeforeSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMe
} }
return nil return nil
} }
func CallbackAfterSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMemberInfo) (err error) { func CallbackAfterSetGroupMemberInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *group.SetGroupMemberInfo) (err error) {
if !config.Config.Callback.CallbackBeforeSetGroupMemberInfo.Enable { if !globalConfig.Callback.CallbackBeforeSetGroupMemberInfo.Enable {
return nil return nil
} }
callbackReq := callbackstruct.CallbackAfterSetGroupMemberInfoReq{ callbackReq := callbackstruct.CallbackAfterSetGroupMemberInfoReq{
@ -214,14 +212,14 @@ func CallbackAfterSetGroupMemberInfo(ctx context.Context, req *group.SetGroupMem
callbackReq.Ex = &req.Ex.Value callbackReq.Ex = &req.Ex.Value
} }
resp := &callbackstruct.CallbackAfterSetGroupMemberInfoResp{} 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 err
} }
return nil return nil
} }
func CallbackQuitGroup(ctx context.Context, req *group.QuitGroupReq) (err error) { func CallbackQuitGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *group.QuitGroupReq) (err error) {
if !config.Config.Callback.CallbackQuitGroup.Enable { if !globalConfig.Callback.CallbackQuitGroup.Enable {
return nil return nil
} }
cbReq := &callbackstruct.CallbackQuitGroupReq{ cbReq := &callbackstruct.CallbackQuitGroupReq{
@ -230,14 +228,14 @@ func CallbackQuitGroup(ctx context.Context, req *group.QuitGroupReq) (err error)
UserID: req.UserID, UserID: req.UserID,
} }
resp := &callbackstruct.CallbackQuitGroupResp{} 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 err
} }
return nil return nil
} }
func CallbackKillGroupMember(ctx context.Context, req *pbgroup.KickGroupMemberReq) (err error) { func CallbackKillGroupMember(ctx context.Context, globalConfig *config.GlobalConfig, req *pbgroup.KickGroupMemberReq) (err error) {
if !config.Config.Callback.CallbackKillGroupMember.Enable { if !globalConfig.Callback.CallbackKillGroupMember.Enable {
return nil return nil
} }
cbReq := &callbackstruct.CallbackKillGroupMemberReq{ cbReq := &callbackstruct.CallbackKillGroupMemberReq{
@ -246,41 +244,41 @@ func CallbackKillGroupMember(ctx context.Context, req *pbgroup.KickGroupMemberRe
KickedUserIDs: req.KickedUserIDs, KickedUserIDs: req.KickedUserIDs,
} }
resp := &callbackstruct.CallbackKillGroupMemberResp{} 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 err
} }
return nil return nil
} }
func CallbackDismissGroup(ctx context.Context, req *callbackstruct.CallbackDisMissGroupReq) (err error) { func CallbackDismissGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *callbackstruct.CallbackDisMissGroupReq) (err error) {
if !config.Config.Callback.CallbackDismissGroup.Enable { if !globalConfig.Callback.CallbackDismissGroup.Enable {
return nil return nil
} }
req.CallbackCommand = callbackstruct.CallbackDisMissGroupCommand req.CallbackCommand = callbackstruct.CallbackDisMissGroupCommand
resp := &callbackstruct.CallbackDisMissGroupResp{} 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 err
} }
return nil return nil
} }
func CallbackApplyJoinGroupBefore(ctx context.Context, req *callbackstruct.CallbackJoinGroupReq) (err error) { func CallbackApplyJoinGroupBefore(ctx context.Context, globalConfig *config.GlobalConfig, req *callbackstruct.CallbackJoinGroupReq) (err error) {
if !config.Config.Callback.CallbackBeforeJoinGroup.Enable { if !globalConfig.Callback.CallbackBeforeJoinGroup.Enable {
return nil return nil
} }
req.CallbackCommand = callbackstruct.CallbackBeforeJoinGroupCommand req.CallbackCommand = callbackstruct.CallbackBeforeJoinGroupCommand
resp := &callbackstruct.CallbackJoinGroupResp{} 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 err
} }
return nil return nil
} }
func CallbackAfterTransferGroupOwner(ctx context.Context, req *pbgroup.TransferGroupOwnerReq) (err error) { func CallbackAfterTransferGroupOwner(ctx context.Context, globalConfig *config.GlobalConfig, req *pbgroup.TransferGroupOwnerReq) (err error) {
if !config.Config.Callback.CallbackAfterTransferGroupOwner.Enable { if !globalConfig.Callback.CallbackAfterTransferGroupOwner.Enable {
return nil return nil
} }
@ -292,13 +290,13 @@ func CallbackAfterTransferGroupOwner(ctx context.Context, req *pbgroup.TransferG
} }
resp := &callbackstruct.CallbackTransferGroupOwnerResp{} 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 err
} }
return nil return nil
} }
func CallbackBeforeInviteUserToGroup(ctx context.Context, req *group.InviteUserToGroupReq) (err error) { func CallbackBeforeInviteUserToGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *group.InviteUserToGroupReq) (err error) {
if !config.Config.Callback.CallbackBeforeInviteUserToGroup.Enable { if !globalConfig.Callback.CallbackBeforeInviteUserToGroup.Enable {
return nil return nil
} }
@ -313,10 +311,10 @@ func CallbackBeforeInviteUserToGroup(ctx context.Context, req *group.InviteUserT
resp := &callbackstruct.CallbackBeforeInviteUserToGroupResp{} resp := &callbackstruct.CallbackBeforeInviteUserToGroupResp{}
err = http.CallBackPostReturn( err = http.CallBackPostReturn(
ctx, ctx,
config.Config.Callback.CallbackUrl, globalConfig.Callback.CallbackUrl,
callbackReq, callbackReq,
resp, resp,
config.Config.Callback.CallbackBeforeInviteUserToGroup, globalConfig.Callback.CallbackBeforeInviteUserToGroup,
) )
if err != nil { if err != nil {
@ -330,8 +328,8 @@ func CallbackBeforeInviteUserToGroup(ctx context.Context, req *group.InviteUserT
return nil return nil
} }
func CallbackAfterJoinGroup(ctx context.Context, req *group.JoinGroupReq) error { func CallbackAfterJoinGroup(ctx context.Context, globalConfig *config.GlobalConfig, req *group.JoinGroupReq) error {
if !config.Config.Callback.CallbackAfterJoinGroup.Enable { if !globalConfig.Callback.CallbackAfterJoinGroup.Enable {
return nil return nil
} }
callbackReq := &callbackstruct.CallbackAfterJoinGroupReq{ callbackReq := &callbackstruct.CallbackAfterJoinGroupReq{
@ -343,14 +341,14 @@ func CallbackAfterJoinGroup(ctx context.Context, req *group.JoinGroupReq) error
InviterUserID: req.InviterUserID, InviterUserID: req.InviterUserID,
} }
resp := &callbackstruct.CallbackAfterJoinGroupResp{} 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 err
} }
return nil return nil
} }
func CallbackBeforeSetGroupInfo(ctx context.Context, req *group.SetGroupInfoReq) error { func CallbackBeforeSetGroupInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *group.SetGroupInfoReq) error {
if !config.Config.Callback.CallbackBeforeSetGroupInfo.Enable { if !globalConfig.Callback.CallbackBeforeSetGroupInfo.Enable {
return nil return nil
} }
callbackReq := &callbackstruct.CallbackBeforeSetGroupInfoReq{ callbackReq := &callbackstruct.CallbackBeforeSetGroupInfoReq{
@ -377,7 +375,7 @@ func CallbackBeforeSetGroupInfo(ctx context.Context, req *group.SetGroupInfoReq)
} }
resp := &callbackstruct.CallbackBeforeSetGroupInfoResp{} 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 return err
} }
@ -399,8 +397,8 @@ func CallbackBeforeSetGroupInfo(ctx context.Context, req *group.SetGroupInfoReq)
utils.NotNilReplace(&req.GroupInfoForSet.Introduction, &resp.Introduction) utils.NotNilReplace(&req.GroupInfoForSet.Introduction, &resp.Introduction)
return nil return nil
} }
func CallbackAfterSetGroupInfo(ctx context.Context, req *group.SetGroupInfoReq) error { func CallbackAfterSetGroupInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *group.SetGroupInfoReq) error {
if !config.Config.Callback.CallbackAfterSetGroupInfo.Enable { if !globalConfig.Callback.CallbackAfterSetGroupInfo.Enable {
return nil return nil
} }
callbackReq := &callbackstruct.CallbackAfterSetGroupInfoReq{ callbackReq := &callbackstruct.CallbackAfterSetGroupInfoReq{
@ -424,7 +422,7 @@ func CallbackAfterSetGroupInfo(ctx context.Context, req *group.SetGroupInfoReq)
callbackReq.ApplyMemberFriend = &req.GroupInfoForSet.ApplyMemberFriend.Value callbackReq.ApplyMemberFriend = &req.GroupInfoForSet.ApplyMemberFriend.Value
} }
resp := &callbackstruct.CallbackAfterSetGroupInfoResp{} 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 err
} }
return nil return nil

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

@ -18,10 +18,9 @@ import (
"context" "context"
"time" "time"
"github.com/OpenIMSDK/tools/mcontext"
pbgroup "github.com/OpenIMSDK/protocol/group" pbgroup "github.com/OpenIMSDK/protocol/group"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/mcontext"
) )
func UpdateGroupInfoMap(ctx context.Context, group *sdkws.GroupInfoForSet) map[string]any { func UpdateGroupInfoMap(ctx context.Context, group *sdkws.GroupInfoForSet) map[string]any {

@ -23,71 +23,63 @@ import (
"strings" "strings"
"time" "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" "github.com/OpenIMSDK/protocol/constant"
pbconversation "github.com/OpenIMSDK/protocol/conversation"
pbgroup "github.com/OpenIMSDK/protocol/group" pbgroup "github.com/OpenIMSDK/protocol/group"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/protocol/wrapperspb"
"github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/mw/specialerror"
"github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/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/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
"github.com/openimsdk/open-im-server/v3/pkg/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 { func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
mongo, err := unrelation.NewMongo() mongo, err := unrelation.NewMongo(config)
if err != nil { if err != nil {
return err return err
} }
rdb, err := cache.NewRedis() rdb, err := cache.NewRedis(config)
if err != nil { if err != nil {
return err return err
} }
groupDB, err := mgo.NewGroupMongo(mongo.GetDatabase()) groupDB, err := mgo.NewGroupMongo(mongo.GetDatabase(config.Mongo.Database))
if err != nil { if err != nil {
return err return err
} }
groupMemberDB, err := mgo.NewGroupMember(mongo.GetDatabase()) groupMemberDB, err := mgo.NewGroupMember(mongo.GetDatabase(config.Mongo.Database))
if err != nil { if err != nil {
return err return err
} }
groupRequestDB, err := mgo.NewGroupRequestMgo(mongo.GetDatabase()) groupRequestDB, err := mgo.NewGroupRequestMgo(mongo.GetDatabase(config.Mongo.Database))
if err != nil { if err != nil {
return err return err
} }
userRpcClient := rpcclient.NewUserRpcClient(client) userRpcClient := rpcclient.NewUserRpcClient(client, config)
msgRpcClient := rpcclient.NewMessageRpcClient(client) msgRpcClient := rpcclient.NewMessageRpcClient(client, config)
conversationRpcClient := rpcclient.NewConversationRpcClient(client) conversationRpcClient := rpcclient.NewConversationRpcClient(client, config)
var gs groupServer var gs groupServer
database := controller.NewGroupDatabase(rdb, groupDB, groupMemberDB, groupRequestDB, tx.NewMongo(mongo.GetClient()), grouphash.NewGroupHashFromGroupServer(&gs)) database := controller.NewGroupDatabase(rdb, groupDB, groupMemberDB, groupRequestDB, tx.NewMongo(mongo.GetClient()), grouphash.NewGroupHashFromGroupServer(&gs))
gs.db = database gs.db = database
gs.User = userRpcClient 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) users, err := userRpcClient.GetUsersInfo(ctx, userIDs)
if err != nil { if err != nil {
return nil, err return nil, err
@ -96,6 +88,7 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e
}) })
gs.conversationRpcClient = conversationRpcClient gs.conversationRpcClient = conversationRpcClient
gs.msgRpcClient = msgRpcClient gs.msgRpcClient = msgRpcClient
gs.config = config
pbgroup.RegisterGroupServer(server, &gs) pbgroup.RegisterGroupServer(server, &gs)
return nil return nil
} }
@ -106,6 +99,7 @@ type groupServer struct {
Notification *notification.GroupNotificationSender Notification *notification.GroupNotificationSender
conversationRpcClient rpcclient.ConversationRpcClient conversationRpcClient rpcclient.ConversationRpcClient
msgRpcClient rpcclient.MessageRpcClient msgRpcClient rpcclient.MessageRpcClient
config *config.GlobalConfig
} }
func (s *groupServer) GetJoinedGroupIDs(ctx context.Context, req *pbgroup.GetJoinedGroupIDsReq) (*pbgroup.GetJoinedGroupIDsResp, error) { 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) { 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) members, err := s.db.FindGroupMemberUser(ctx, nil, req.UserID)
if err != nil { if err != nil {
return nil, err return nil, err
@ -126,21 +119,20 @@ func (s *groupServer) NotificationUserInfoUpdate(ctx context.Context, req *pbgro
} }
groupIDs = append(groupIDs, member.GroupID) groupIDs = append(groupIDs, member.GroupID)
} }
log.ZInfo(ctx, "NotificationUserInfoUpdate", "joinGroupNum", len(members), "updateNum", len(groupIDs), "updateGroupIDs", groupIDs)
for _, groupID := range groupIDs { for _, groupID := range groupIDs {
if err := s.Notification.GroupMemberInfoSetNotification(ctx, groupID, req.UserID); err != nil { if err = s.Notification.GroupMemberInfoSetNotification(ctx, groupID, req.UserID); err != nil {
log.ZError(ctx, "NotificationUserInfoUpdate setGroupMemberInfo notification failed", err, "groupID", groupID) return nil, err
} }
} }
if err := s.db.DeleteGroupMemberHash(ctx, groupIDs); err != nil { if err = s.db.DeleteGroupMemberHash(ctx, groupIDs); err != nil {
log.ZError(ctx, "NotificationUserInfoUpdate DeleteGroupMemberHash", err, "groupID", groupIDs) return nil, err
} }
return &pbgroup.NotificationUserInfoUpdateResp{}, nil return &pbgroup.NotificationUserInfoUpdateResp{}, nil
} }
func (s *groupServer) CheckGroupAdmin(ctx context.Context, groupID string) error { 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)) groupMember, err := s.db.TakeGroupMember(ctx, groupID, mcontext.GetOpUserID(ctx))
if err != nil { if err != nil {
return err return err
@ -205,7 +197,7 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR
if req.OwnerUserID == "" { if req.OwnerUserID == "" {
return nil, errs.ErrArgs.Wrap("no group owner") 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 return nil, err
} }
userIDs := append(append(req.MemberUserIDs, req.AdminUserIDs...), req.OwnerUserID) 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") return nil, errs.ErrUserIDNotFound.Wrap("user not found")
} }
// Callback Before create Group // Callback Before create Group
if err := CallbackBeforeCreateGroup(ctx, req); err != nil { if err := CallbackBeforeCreateGroup(ctx, s.config, req); err != nil {
return nil, err return nil, err
} }
var groupMembers []*relationtb.GroupMemberModel var groupMembers []*relationtb.GroupMemberModel
@ -243,7 +235,7 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR
JoinTime: time.Now(), JoinTime: time.Now(),
MuteEndTime: time.UnixMilli(0), 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 return err
} }
groupMembers = append(groupMembers, groupMember) groupMembers = append(groupMembers, groupMember)
@ -311,7 +303,7 @@ func (s *groupServer) CreateGroup(ctx context.Context, req *pbgroup.CreateGroupR
AdminUserIDs: req.AdminUserIDs, AdminUserIDs: req.AdminUserIDs,
} }
if err := CallbackAfterCreateGroup(ctx, reqCallBackAfter); err != nil { if err := CallbackAfterCreateGroup(ctx, s.config, reqCallBackAfter); err != nil {
return nil, err 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) { func (s *groupServer) GetJoinedGroupList(ctx context.Context, req *pbgroup.GetJoinedGroupListReq) (*pbgroup.GetJoinedGroupListResp, error) {
resp := &pbgroup.GetJoinedGroupListResp{} 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 return nil, err
} }
total, members, err := s.db.PageGetJoinGroup(ctx, req.FromUserID, req.Pagination) 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 groupMember *relationtb.GroupMemberModel
var opUserID string var opUserID string
if !authverify.IsAppManagerUid(ctx) { if !authverify.IsAppManagerUid(ctx, s.config) {
opUserID = mcontext.GetOpUserID(ctx) opUserID = mcontext.GetOpUserID(ctx)
var err error var err error
groupMember, err = s.db.TakeGroupMember(ctx, req.GroupID, opUserID) 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 return nil, err
} }
if group.NeedVerification == constant.AllNeedVerification { if group.NeedVerification == constant.AllNeedVerification {
if !authverify.IsAppManagerUid(ctx) { if !authverify.IsAppManagerUid(ctx, s.config) {
if !(groupMember.RoleLevel == constant.GroupOwner || groupMember.RoleLevel == constant.GroupAdmin) { if !(groupMember.RoleLevel == constant.GroupOwner || groupMember.RoleLevel == constant.GroupAdmin) {
var requests []*relationtb.GroupRequestModel var requests []*relationtb.GroupRequestModel
for _, userID := range req.InvitedUserIDs { for _, userID := range req.InvitedUserIDs {
@ -446,7 +438,7 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite
JoinTime: time.Now(), JoinTime: time.Now(),
MuteEndTime: time.UnixMilli(0), 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 return nil, err
} }
groupMembers = append(groupMembers, member) groupMembers = append(groupMembers, member)
@ -546,7 +538,7 @@ func (s *groupServer) KickGroupMember(ctx context.Context, req *pbgroup.KickGrou
for i, member := range members { for i, member := range members {
memberMap[member.UserID] = members[i] memberMap[member.UserID] = members[i]
} }
isAppManagerUid := authverify.IsAppManagerUid(ctx) isAppManagerUid := authverify.IsAppManagerUid(ctx, s.config)
opMember := memberMap[opUserID] opMember := memberMap[opUserID]
for _, userID := range req.KickedUserIDs { for _, userID := range req.KickedUserIDs {
member, ok := memberMap[userID] member, ok := memberMap[userID]
@ -618,7 +610,7 @@ func (s *groupServer) KickGroupMember(ctx context.Context, req *pbgroup.KickGrou
return nil, err return nil, err
} }
if err := CallbackKillGroupMember(ctx, req); err != nil { if err := CallbackKillGroupMember(ctx, s.config, req); err != nil {
return nil, err return nil, err
} }
return resp, nil 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) { if !utils.Contain(req.HandleResult, constant.GroupResponseAgree, constant.GroupResponseRefuse) {
return nil, errs.ErrArgs.Wrap("HandleResult unknown") 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)) groupMember, err := s.db.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx))
if err != nil { if err != nil {
return nil, err 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") return nil, errs.ErrGroupRequestHandled.Wrap("group request already processed")
} }
var inGroup bool var inGroup bool
if _, err := s.db.TakeGroupMember(ctx, req.GroupID, req.FromUserID); err == nil { if _, takeErr := s.db.TakeGroupMember(ctx, req.GroupID, req.FromUserID); takeErr == nil {
inGroup = true // 已经在群里了 inGroup = true // Already in group
} else if !s.IsNotFound(err) { } else if !s.IsNotFound(err) {
return nil, err return nil, err
} }
@ -788,7 +780,7 @@ func (s *groupServer) GroupApplicationResponse(ctx context.Context, req *pbgroup
OperatorUserID: mcontext.GetOpUserID(ctx), OperatorUserID: mcontext.GetOpUserID(ctx),
Ex: groupRequest.Ex, 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 return nil, err
} }
} }
@ -836,7 +828,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq)
Ex: req.Ex, Ex: req.Ex,
} }
if err = CallbackApplyJoinGroupBefore(ctx, reqCall); err != nil { if err = CallbackApplyJoinGroupBefore(ctx, s.config, reqCall); err != nil {
return nil, err return nil, err
} }
_, err = s.db.TakeGroupMember(ctx, req.GroupID, req.InviterUserID) _, 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(), JoinTime: time.Now(),
MuteEndTime: time.UnixMilli(0), 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 return nil, err
} }
if err := s.db.CreateGroup(ctx, nil, []*relationtb.GroupMemberModel{groupMember}); err != nil { 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 return nil, err
} }
s.Notification.MemberEnterNotification(ctx, req.GroupID, req.InviterUserID) 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 nil, err
} }
return resp, nil return resp, nil
@ -882,7 +874,7 @@ func (s *groupServer) JoinGroup(ctx context.Context, req *pbgroup.JoinGroupReq)
HandledTime: time.Unix(0, 0), HandledTime: time.Unix(0, 0),
Ex: req.Ex, 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 return nil, err
} }
s.Notification.JoinGroupApplicationNotification(ctx, req) s.Notification.JoinGroupApplicationNotification(ctx, req)
@ -894,7 +886,7 @@ func (s *groupServer) QuitGroup(ctx context.Context, req *pbgroup.QuitGroupReq)
if req.UserID == "" { if req.UserID == "" {
req.UserID = mcontext.GetOpUserID(ctx) req.UserID = mcontext.GetOpUserID(ctx)
} else { } else {
if err := authverify.CheckAccessV3(ctx, req.UserID); err != nil { if err := authverify.CheckAccessV3(ctx, req.UserID, s.config); err != nil {
return nil, err return nil, err
} }
} }
@ -918,7 +910,7 @@ func (s *groupServer) QuitGroup(ctx context.Context, req *pbgroup.QuitGroupReq)
} }
// callback // callback
if err := CallbackQuitGroup(ctx, req); err != nil { if err := CallbackQuitGroup(ctx, s.config, req); err != nil {
return nil, err return nil, err
} }
return resp, nil 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) { func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInfoReq) (*pbgroup.SetGroupInfoResp, error) {
var opMember *relationtb.GroupMemberModel var opMember *relationtb.GroupMemberModel
if !authverify.IsAppManagerUid(ctx) { if !authverify.IsAppManagerUid(ctx, s.config) {
var err error var err error
opMember, err = s.db.TakeGroupMember(ctx, req.GroupInfoForSet.GroupID, mcontext.GetOpUserID(ctx)) opMember, err = s.db.TakeGroupMember(ctx, req.GroupInfoForSet.GroupID, mcontext.GetOpUserID(ctx))
if err != nil { if err != nil {
@ -948,7 +940,7 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf
return nil, err return nil, err
} }
} }
if err := CallbackBeforeSetGroupInfo(ctx, req); err != nil { if err := CallbackBeforeSetGroupInfo(ctx, s.config, req); err != nil {
return nil, err return nil, err
} }
group, err := s.db.TakeGroup(ctx, req.GroupInfoForSet.GroupID) 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 return nil, err
} }
if group.Status == constant.GroupStatusDismissed { if group.Status == constant.GroupStatusDismissed {
return nil, utils.Wrap(errs.ErrDismissedAlready, "") return nil, errs.Wrap(errs.ErrDismissedAlready)
} }
resp := &pbgroup.SetGroupInfoResp{} resp := &pbgroup.SetGroupInfoResp{}
count, err := s.db.FindGroupMemberNum(ctx, group.GroupID) 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 { if num > 0 {
_ = s.Notification.GroupInfoSetNotification(ctx, tips) _ = 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 nil, err
} }
return resp, nil return resp, nil
@ -1054,7 +1046,7 @@ func (s *groupServer) TransferGroupOwner(ctx context.Context, req *pbgroup.Trans
if newOwner == nil { if newOwner == nil {
return nil, errs.ErrArgs.Wrap("NewOwnerUser not in group " + req.NewOwnerUserID) 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) { if !(mcontext.GetOpUserID(ctx) == oldOwner.UserID && oldOwner.RoleLevel == constant.GroupOwner) {
return nil, errs.ErrNoPermission.Wrap("no permission transfer group owner") 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 return nil, err
} }
if err := CallbackAfterTransferGroupOwner(ctx, req); err != nil { if err := CallbackAfterTransferGroupOwner(ctx, s.config, req); err != nil {
return nil, err return nil, err
} }
s.Notification.GroupOwnerTransferredNotification(ctx, req) s.Notification.GroupOwnerTransferredNotification(ctx, req)
@ -1195,7 +1187,7 @@ func (s *groupServer) DismissGroup(ctx context.Context, req *pbgroup.DismissGrou
if err != nil { if err != nil {
return nil, err return nil, err
} }
if !authverify.IsAppManagerUid(ctx) { if !authverify.IsAppManagerUid(ctx, s.config) {
if owner.UserID != mcontext.GetOpUserID(ctx) { if owner.UserID != mcontext.GetOpUserID(ctx) {
return nil, errs.ErrNoPermission.Wrap("not group owner") 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 { if err != nil {
return nil, err 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") return nil, errs.ErrDismissedAlready.Wrap("group status is dismissed")
} }
if err := s.db.DismissGroup(ctx, req.GroupID, req.DeleteMember); err != nil { 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, MembersID: membersID,
GroupType: string(group.GroupType), GroupType: string(group.GroupType),
} }
if err := CallbackDismissGroup(ctx, reqCall); err != nil { if err := CallbackDismissGroup(ctx, s.config, reqCall); err != nil {
return nil, err 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 { if err := s.PopulateGroupMember(ctx, member); err != nil {
return nil, err return nil, err
} }
if !authverify.IsAppManagerUid(ctx) { if !authverify.IsAppManagerUid(ctx, s.config) {
opMember, err := s.db.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx)) opMember, err := s.db.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx))
if err != nil { if err != nil {
return nil, err 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 { if err := s.PopulateGroupMember(ctx, member); err != nil {
return nil, err return nil, err
} }
if !authverify.IsAppManagerUid(ctx) { if !authverify.IsAppManagerUid(ctx, s.config) {
opMember, err := s.db.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx)) opMember, err := s.db.TakeGroupMember(ctx, req.GroupID, mcontext.GetOpUserID(ctx))
if err != nil { if err != nil {
return nil, err return nil, err
@ -1346,7 +1338,7 @@ func (s *groupServer) SetGroupMemberInfo(ctx context.Context, req *pbgroup.SetGr
if opUserID == "" { if opUserID == "" {
return nil, errs.ErrNoPermission.Wrap("no op user id") return nil, errs.ErrNoPermission.Wrap("no op user id")
} }
isAppManagerUid := authverify.IsAppManagerUid(ctx) isAppManagerUid := authverify.IsAppManagerUid(ctx, s.config)
for i := range req.Members { for i := range req.Members {
req.Members[i].FaceURL = nil 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++ { 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 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++ { 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 return nil, err
} }
} }

@ -17,17 +17,14 @@ package msg
import ( import (
"context" "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/constant"
"github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/msg"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
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) { 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, Seqs: req.Seqs,
ContentType: conversation.ConversationType, ContentType: conversation.ConversationType,
} }
if err = CallbackSingleMsgRead(ctx, req_callback); err != nil { if err = CallbackSingleMsgRead(ctx, m.config, req_callback); err != nil {
return nil, err return nil, err
} }
@ -209,7 +206,7 @@ func (m *msgServer) MarkConversationAsRead(
UnreadMsgNum: req.HasReadSeq, UnreadMsgNum: req.HasReadSeq,
ContentType: int64(conversation.ConversationType), ContentType: int64(conversation.ConversationType),
} }
if err := CallbackGroupMsgRead(ctx, reqCall); err != nil { if err := CallbackGroupMsgRead(ctx, m.config, reqCall); err != nil {
return nil, err return nil, err
} }

@ -17,25 +17,18 @@ package msg
import ( import (
"context" "context"
"github.com/OpenIMSDK/protocol/sdkws"
"google.golang.org/protobuf/proto"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
pbchat "github.com/OpenIMSDK/protocol/msg" pbchat "github.com/OpenIMSDK/protocol/msg"
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/http" "github.com/openimsdk/open-im-server/v3/pkg/common/http"
"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 { func toCommonCallback(ctx context.Context, msg *pbchat.SendMsgReq, command string) cbapi.CommonCallbackReq {
return cbapi.CommonCallbackReq{ return cbapi.CommonCallbackReq{
SendID: msg.MsgData.SendID, SendID: msg.MsgData.SendID,
@ -69,8 +62,8 @@ func GetContent(msg *sdkws.MsgData) string {
} }
} }
func callbackBeforeSendSingleMsg(ctx context.Context, msg *pbchat.SendMsgReq) error { func callbackBeforeSendSingleMsg(ctx context.Context, globalConfig *config.GlobalConfig, msg *pbchat.SendMsgReq) error {
if !config.Config.Callback.CallbackBeforeSendSingleMsg.Enable || msg.MsgData.ContentType == constant.Typing { if !globalConfig.Callback.CallbackBeforeSendSingleMsg.Enable || msg.MsgData.ContentType == constant.Typing {
return nil return nil
} }
req := &cbapi.CallbackBeforeSendSingleMsgReq{ req := &cbapi.CallbackBeforeSendSingleMsgReq{
@ -78,14 +71,14 @@ func callbackBeforeSendSingleMsg(ctx context.Context, msg *pbchat.SendMsgReq) er
RecvID: msg.MsgData.RecvID, RecvID: msg.MsgData.RecvID,
} }
resp := &cbapi.CallbackBeforeSendSingleMsgResp{} resp := &cbapi.CallbackBeforeSendSingleMsgResp{}
if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackBeforeSendSingleMsg); err != nil { if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackBeforeSendSingleMsg); err != nil {
return err return err
} }
return nil return nil
} }
func callbackAfterSendSingleMsg(ctx context.Context, msg *pbchat.SendMsgReq) error { func callbackAfterSendSingleMsg(ctx context.Context, globalConfig *config.GlobalConfig, msg *pbchat.SendMsgReq) error {
if !config.Config.Callback.CallbackAfterSendSingleMsg.Enable || msg.MsgData.ContentType == constant.Typing { if !globalConfig.Callback.CallbackAfterSendSingleMsg.Enable || msg.MsgData.ContentType == constant.Typing {
return nil return nil
} }
req := &cbapi.CallbackAfterSendSingleMsgReq{ req := &cbapi.CallbackAfterSendSingleMsgReq{
@ -93,14 +86,14 @@ func callbackAfterSendSingleMsg(ctx context.Context, msg *pbchat.SendMsgReq) err
RecvID: msg.MsgData.RecvID, RecvID: msg.MsgData.RecvID,
} }
resp := &cbapi.CallbackAfterSendSingleMsgResp{} resp := &cbapi.CallbackAfterSendSingleMsgResp{}
if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackAfterSendSingleMsg); err != nil { if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackAfterSendSingleMsg); err != nil {
return err return err
} }
return nil return nil
} }
func callbackBeforeSendGroupMsg(ctx context.Context, msg *pbchat.SendMsgReq) error { func callbackBeforeSendGroupMsg(ctx context.Context, globalConfig *config.GlobalConfig, msg *pbchat.SendMsgReq) error {
if !config.Config.Callback.CallbackBeforeSendGroupMsg.Enable || msg.MsgData.ContentType == constant.Typing { if !globalConfig.Callback.CallbackBeforeSendGroupMsg.Enable || msg.MsgData.ContentType == constant.Typing {
return nil return nil
} }
req := &cbapi.CallbackBeforeSendGroupMsgReq{ req := &cbapi.CallbackBeforeSendGroupMsgReq{
@ -108,14 +101,14 @@ func callbackBeforeSendGroupMsg(ctx context.Context, msg *pbchat.SendMsgReq) err
GroupID: msg.MsgData.GroupID, GroupID: msg.MsgData.GroupID,
} }
resp := &cbapi.CallbackBeforeSendGroupMsgResp{} resp := &cbapi.CallbackBeforeSendGroupMsgResp{}
if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackBeforeSendGroupMsg); err != nil { if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackBeforeSendGroupMsg); err != nil {
return err return err
} }
return nil return nil
} }
func callbackAfterSendGroupMsg(ctx context.Context, msg *pbchat.SendMsgReq) error { func callbackAfterSendGroupMsg(ctx context.Context, globalConfig *config.GlobalConfig, msg *pbchat.SendMsgReq) error {
if !config.Config.Callback.CallbackAfterSendGroupMsg.Enable || msg.MsgData.ContentType == constant.Typing { if !globalConfig.Callback.CallbackAfterSendGroupMsg.Enable || msg.MsgData.ContentType == constant.Typing {
return nil return nil
} }
req := &cbapi.CallbackAfterSendGroupMsgReq{ req := &cbapi.CallbackAfterSendGroupMsgReq{
@ -123,21 +116,21 @@ func callbackAfterSendGroupMsg(ctx context.Context, msg *pbchat.SendMsgReq) erro
GroupID: msg.MsgData.GroupID, GroupID: msg.MsgData.GroupID,
} }
resp := &cbapi.CallbackAfterSendGroupMsgResp{} resp := &cbapi.CallbackAfterSendGroupMsgResp{}
if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackAfterSendGroupMsg); err != nil { if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackAfterSendGroupMsg); err != nil {
return err return err
} }
return nil return nil
} }
func callbackMsgModify(ctx context.Context, msg *pbchat.SendMsgReq) error { func callbackMsgModify(ctx context.Context, globalConfig *config.GlobalConfig, msg *pbchat.SendMsgReq) error {
if !config.Config.Callback.CallbackMsgModify.Enable || msg.MsgData.ContentType != constant.Text { if !globalConfig.Callback.CallbackMsgModify.Enable || msg.MsgData.ContentType != constant.Text {
return nil return nil
} }
req := &cbapi.CallbackMsgModifyCommandReq{ req := &cbapi.CallbackMsgModifyCommandReq{
CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackMsgModifyCommand), CommonCallbackReq: toCommonCallback(ctx, msg, cbapi.CallbackMsgModifyCommand),
} }
resp := &cbapi.CallbackMsgModifyCommandResp{} resp := &cbapi.CallbackMsgModifyCommandResp{}
if err := http.CallBackPostReturn(ctx, cbURL(), req, resp, config.Config.Callback.CallbackMsgModify); err != nil { if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackMsgModify); err != nil {
return err return err
} }
if resp.Content != nil { if resp.Content != nil {
@ -162,34 +155,34 @@ func callbackMsgModify(ctx context.Context, msg *pbchat.SendMsgReq) error {
log.ZDebug(ctx, "callbackMsgModify", "msg", msg.MsgData) log.ZDebug(ctx, "callbackMsgModify", "msg", msg.MsgData)
return nil return nil
} }
func CallbackGroupMsgRead(ctx context.Context, req *cbapi.CallbackGroupMsgReadReq) error { func CallbackGroupMsgRead(ctx context.Context, globalConfig *config.GlobalConfig, req *cbapi.CallbackGroupMsgReadReq) error {
if !config.Config.Callback.CallbackGroupMsgRead.Enable || req.ContentType != constant.Text { if !globalConfig.Callback.CallbackGroupMsgRead.Enable || req.ContentType != constant.Text {
return nil return nil
} }
req.CallbackCommand = cbapi.CallbackGroupMsgReadCommand req.CallbackCommand = cbapi.CallbackGroupMsgReadCommand
resp := &cbapi.CallbackGroupMsgReadResp{} 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 err
} }
return nil return nil
} }
func CallbackSingleMsgRead(ctx context.Context, req *cbapi.CallbackSingleMsgReadReq) error { func CallbackSingleMsgRead(ctx context.Context, globalConfig *config.GlobalConfig, req *cbapi.CallbackSingleMsgReadReq) error {
if !config.Config.Callback.CallbackSingleMsgRead.Enable || req.ContentType != constant.Text { if !globalConfig.Callback.CallbackSingleMsgRead.Enable || req.ContentType != constant.Text {
return nil return nil
} }
req.CallbackCommand = cbapi.CallbackSingleMsgRead req.CallbackCommand = cbapi.CallbackSingleMsgRead
resp := &cbapi.CallbackSingleMsgReadResp{} 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 err
} }
return nil return nil
} }
func CallbackAfterRevokeMsg(ctx context.Context, req *pbchat.RevokeMsgReq) error { func CallbackAfterRevokeMsg(ctx context.Context, globalConfig *config.GlobalConfig, req *pbchat.RevokeMsgReq) error {
if !config.Config.Callback.CallbackAfterRevokeMsg.Enable { if !globalConfig.Callback.CallbackAfterRevokeMsg.Enable {
return nil return nil
} }
callbackReq := &cbapi.CallbackAfterRevokeMsgReq{ callbackReq := &cbapi.CallbackAfterRevokeMsgReq{
@ -199,7 +192,7 @@ func CallbackAfterRevokeMsg(ctx context.Context, req *pbchat.RevokeMsgReq) error
UserID: req.UserID, UserID: req.UserID,
} }
resp := &cbapi.CallbackAfterRevokeMsgResp{} 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 err
} }
return nil return nil

@ -17,14 +17,13 @@ package msg
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/conversation" "github.com/OpenIMSDK/protocol/conversation"
"github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/msg"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/utils" "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 { func (m *msgServer) getMinSeqs(maxSeqs map[string]int64) map[string]int64 {
@ -46,7 +45,7 @@ func (m *msgServer) ClearConversationsMsg(
ctx context.Context, ctx context.Context,
req *msg.ClearConversationsMsgReq, req *msg.ClearConversationsMsgReq,
) (*msg.ClearConversationsMsgResp, error) { ) (*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 return nil, err
} }
if err := m.clearConversation(ctx, req.ConversationIDs, req.UserID, req.DeleteSyncOpt); err != nil { if err := m.clearConversation(ctx, req.ConversationIDs, req.UserID, req.DeleteSyncOpt); err != nil {
@ -59,7 +58,7 @@ func (m *msgServer) UserClearAllMsg(
ctx context.Context, ctx context.Context,
req *msg.UserClearAllMsgReq, req *msg.UserClearAllMsgReq,
) (*msg.UserClearAllMsgResp, error) { ) (*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 return nil, err
} }
conversationIDs, err := m.ConversationLocalCache.GetConversationIDs(ctx, req.UserID) 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) { 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 return nil, err
} }
isSyncSelf, isSyncOther := m.validateDeleteSyncOpt(req.DeleteSyncOpt) isSyncSelf, isSyncOther := m.validateDeleteSyncOpt(req.DeleteSyncOpt)
@ -122,7 +121,7 @@ func (m *msgServer) DeleteMsgPhysical(
ctx context.Context, ctx context.Context,
req *msg.DeleteMsgPhysicalReq, req *msg.DeleteMsgPhysicalReq,
) (*msg.DeleteMsgPhysicalResp, error) { ) (*msg.DeleteMsgPhysicalResp, error) {
if err := authverify.CheckAdmin(ctx); err != nil { if err := authverify.CheckAdmin(ctx, m.config); err != nil {
return nil, err return nil, err
} }
remainTime := utils.GetCurrentTimestampBySecond() - req.Timestamp remainTime := utils.GetCurrentTimestampBySecond() - req.Timestamp

@ -21,21 +21,20 @@ import (
"github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/msg"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "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 { switch {
case req.MsgData.ContentType == constant.HasReadReceipt && req.MsgData.SessionType == constant.SingleChatType: case req.MsgData.ContentType == constant.HasReadReceipt && req.MsgData.SessionType == constant.SingleChatType:
if !config.Config.SingleMessageHasReadReceiptEnable { if !globalConfig.SingleMessageHasReadReceiptEnable {
return nil, errs.ErrMessageHasReadDisable.Wrap() return nil, errs.ErrMessageHasReadDisable.Wrap()
} }
return req.MsgData, nil return req.MsgData, nil
case req.MsgData.ContentType == constant.HasReadReceipt && req.MsgData.SessionType == constant.SuperGroupChatType: case req.MsgData.ContentType == constant.HasReadReceipt && req.MsgData.SessionType == constant.SuperGroupChatType:
if !config.Config.GroupMessageHasReadReceiptEnable { if !globalConfig.GroupMessageHasReadReceiptEnable {
return nil, errs.ErrMessageHasReadDisable.Wrap() return nil, errs.ErrMessageHasReadDisable.Wrap()
} }
return req.MsgData, nil return req.MsgData, nil

@ -19,8 +19,6 @@ import (
"encoding/json" "encoding/json"
"time" "time"
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/msg"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
@ -28,8 +26,7 @@ import (
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
unrelationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" 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 { if req.Seq < 0 {
return nil, errs.ErrArgs.Wrap("seq is invalid") 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 return nil, err
} }
user, err := m.User.GetUserInfo(ctx, req.UserID) 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]) data, _ := json.Marshal(msgs[0])
log.ZInfo(ctx, "GetMsgBySeqs", "conversationID", req.ConversationID, "seq", req.Seq, "msg", string(data)) log.ZInfo(ctx, "GetMsgBySeqs", "conversationID", req.ConversationID, "seq", req.Seq, "msg", string(data))
var role int32 var role int32
if !authverify.IsAppManagerUid(ctx) { if !authverify.IsAppManagerUid(ctx, m.config) {
switch msgs[0].SessionType { switch msgs[0].SessionType {
case constant.SingleChatType: 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 return nil, err
} }
role = user.AppMangerLevel role = user.AppMangerLevel
@ -112,11 +109,11 @@ func (m *msgServer) RevokeMsg(ctx context.Context, req *msg.RevokeMsgReq) (*msg.
} }
revokerUserID := mcontext.GetOpUserID(ctx) revokerUserID := mcontext.GetOpUserID(ctx)
var flag bool var flag bool
if len(config.Config.Manager.UserID) > 0 { if len(m.config.Manager.UserID) > 0 {
flag = utils.Contain(revokerUserID, config.Config.Manager.UserID...) flag = utils.Contain(revokerUserID, m.config.Manager.UserID...)
} }
if len(config.Config.Manager.UserID) == 0 && len(config.Config.IMAdmin.UserID) > 0 { if len(m.config.Manager.UserID) == 0 && len(m.config.IMAdmin.UserID) > 0 {
flag = utils.Contain(revokerUserID, config.Config.IMAdmin.UserID...) flag = utils.Contain(revokerUserID, m.config.IMAdmin.UserID...)
} }
tips := sdkws.RevokeMsgTips{ tips := sdkws.RevokeMsgTips{
RevokerUserID: revokerUserID, 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 { if err := m.notificationSender.NotificationWithSesstionType(ctx, req.UserID, recvID, constant.MsgRevokeNotification, msgs[0].SessionType, &tips); err != nil {
return nil, err return nil, err
} }
if err = CallbackAfterRevokeMsg(ctx, req); err != nil { if err = CallbackAfterRevokeMsg(ctx, m.config, req); err != nil {
return nil, err return nil, err
} }
return &msg.RevokeMsgResp{}, nil return &msg.RevokeMsgResp{}, nil

@ -17,9 +17,6 @@ package msg
import ( import (
"context" "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" "github.com/OpenIMSDK/protocol/constant"
pbconversation "github.com/OpenIMSDK/protocol/conversation" pbconversation "github.com/OpenIMSDK/protocol/conversation"
pbmsg "github.com/OpenIMSDK/protocol/msg" pbmsg "github.com/OpenIMSDK/protocol/msg"
@ -29,12 +26,14 @@ import (
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils" "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) { func (m *msgServer) SendMsg(ctx context.Context, req *pbmsg.SendMsgReq) (resp *pbmsg.SendMsgResp, error error) {
resp = &pbmsg.SendMsgResp{} resp = &pbmsg.SendMsgResp{}
if req.MsgData != nil { if req.MsgData != nil {
flag := isMessageHasReadEnabled(req.MsgData) flag := isMessageHasReadEnabled(req.MsgData, m.config)
if !flag { if !flag {
return nil, errs.ErrMessageHasReadDisable.Wrap() return nil, errs.ErrMessageHasReadDisable.Wrap()
} }
@ -62,11 +61,11 @@ func (m *msgServer) sendMsgSuperGroupChat(
prommetrics.GroupChatMsgProcessFailedCounter.Inc() prommetrics.GroupChatMsgProcessFailedCounter.Inc()
return nil, err return nil, err
} }
if err = callbackBeforeSendGroupMsg(ctx, req); err != nil { if err = callbackBeforeSendGroupMsg(ctx, m.config, req); err != nil {
return nil, err return nil, err
} }
if err := callbackMsgModify(ctx, req); err != nil { if err := callbackMsgModify(ctx, m.config, req); err != nil {
return nil, err return nil, err
} }
err = m.MsgDatabase.MsgToMQ(ctx, utils.GenConversationUniqueKeyForGroup(req.MsgData.GroupID), req.MsgData) 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 { if req.MsgData.ContentType == constant.AtText {
go m.setConversationAtInfo(ctx, req.MsgData) 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) log.ZWarn(ctx, "CallbackAfterSendGroupMsg", err)
} }
prommetrics.GroupChatMsgProcessSuccessCounter.Inc() prommetrics.GroupChatMsgProcessSuccessCounter.Inc()
@ -108,7 +107,7 @@ func (m *msgServer) setConversationAtInfo(nctx context.Context, msg *sdkws.MsgDa
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAll} conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAll}
} else { //@Everyone and @other people } else { //@Everyone and @other people
conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAllAtMe} conversation.GroupAtType = &wrapperspb.Int32Value{Value: constant.AtAllAtMe}
err := m.Conversation.SetConversations(ctx, atUserID, conversation) err = m.Conversation.SetConversations(ctx, atUserID, conversation)
if err != nil { if err != nil {
log.ZWarn(ctx, "SetConversations", err, "userID", atUserID, "conversation", conversation) 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() prommetrics.SingleChatMsgProcessFailedCounter.Inc()
return nil, nil return nil, nil
} else { } else {
if err = callbackBeforeSendSingleMsg(ctx, req); err != nil { if err = callbackBeforeSendSingleMsg(ctx, m.config, req); err != nil {
return nil, err return nil, err
} }
if err := callbackMsgModify(ctx, req); err != nil { if err := callbackMsgModify(ctx, m.config, req); err != nil {
return nil, err return nil, err
} }
if err := m.MsgDatabase.MsgToMQ(ctx, utils.GenConversationUniqueKeyForSingle(req.MsgData.SendID, req.MsgData.RecvID), req.MsgData); err != nil { if err := m.MsgDatabase.MsgToMQ(ctx, utils.GenConversationUniqueKeyForSingle(req.MsgData.SendID, req.MsgData.RecvID), req.MsgData); err != nil {
prommetrics.SingleChatMsgProcessFailedCounter.Inc() prommetrics.SingleChatMsgProcessFailedCounter.Inc()
return nil, err return nil, err
} }
err = callbackAfterSendSingleMsg(ctx, req) err = callbackAfterSendSingleMsg(ctx, m.config, req)
if err != nil { if err != nil {
log.ZWarn(ctx, "CallbackAfterSendSingleMsg", err, "req", req) log.ZWarn(ctx, "CallbackAfterSendSingleMsg", err, "req", req)
} }

@ -15,20 +15,17 @@
package msg package msg
import ( import (
"context"
"google.golang.org/grpc"
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/conversation" "github.com/OpenIMSDK/protocol/conversation"
"github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/msg"
"github.com/OpenIMSDK/tools/discoveryregistry" "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/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/localcache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/localcache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"google.golang.org/grpc"
) )
type ( type (
@ -44,6 +41,7 @@ type (
ConversationLocalCache *localcache.ConversationLocalCache ConversationLocalCache *localcache.ConversationLocalCache
Handlers MessageInterceptorChain Handlers MessageInterceptorChain
notificationSender *rpcclient.NotificationSender notificationSender *rpcclient.NotificationSender
config *config.GlobalConfig
} }
) )
@ -51,36 +49,36 @@ func (m *msgServer) addInterceptorHandler(interceptorFunc ...MessageInterceptorF
m.Handlers = append(m.Handlers, interceptorFunc...) m.Handlers = append(m.Handlers, interceptorFunc...)
} }
func (m *msgServer) execInterceptorHandler(ctx context.Context, req *msg.SendMsgReq) error { //func (m *msgServer) execInterceptorHandler(ctx context.Context, config *config.GlobalConfig, req *msg.SendMsgReq) error {
for _, handler := range m.Handlers { // for _, handler := range m.Handlers {
msgData, err := handler(ctx, req) // msgData, err := handler(ctx, config, req)
if err != nil { // if err != nil {
return err // return err
} // }
req.MsgData = msgData // req.MsgData = msgData
} // }
return nil // return nil
} //}
func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
rdb, err := cache.NewRedis() rdb, err := cache.NewRedis(config)
if err != nil { if err != nil {
return err return err
} }
mongo, err := unrelation.NewMongo() mongo, err := unrelation.NewMongo(config)
if err != nil { if err != nil {
return err return err
} }
if err := mongo.CreateMsgIndex(); err != nil { if err := mongo.CreateMsgIndex(); err != nil {
return err return err
} }
cacheModel := cache.NewMsgCacheModel(rdb) cacheModel := cache.NewMsgCacheModel(rdb, config)
msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase()) msgDocModel := unrelation.NewMsgMongoDriver(mongo.GetDatabase(config.Mongo.Database))
conversationClient := rpcclient.NewConversationRpcClient(client) conversationClient := rpcclient.NewConversationRpcClient(client, config)
userRpcClient := rpcclient.NewUserRpcClient(client) userRpcClient := rpcclient.NewUserRpcClient(client, config)
groupRpcClient := rpcclient.NewGroupRpcClient(client) groupRpcClient := rpcclient.NewGroupRpcClient(client, config)
friendRpcClient := rpcclient.NewFriendRpcClient(client) friendRpcClient := rpcclient.NewFriendRpcClient(client, config)
msgDatabase, err := controller.NewCommonMsgDatabase(msgDocModel, cacheModel) msgDatabase, err := controller.NewCommonMsgDatabase(msgDocModel, cacheModel, config)
if err != nil { if err != nil {
return err return err
} }
@ -93,8 +91,9 @@ func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) e
GroupLocalCache: localcache.NewGroupLocalCache(&groupRpcClient), GroupLocalCache: localcache.NewGroupLocalCache(&groupRpcClient),
ConversationLocalCache: localcache.NewConversationLocalCache(&conversationClient), ConversationLocalCache: localcache.NewConversationLocalCache(&conversationClient),
friend: &friendRpcClient, friend: &friendRpcClient,
config: config,
} }
s.notificationSender = rpcclient.NewNotificationSender(rpcclient.WithLocalSendMsg(s.SendMsg)) s.notificationSender = rpcclient.NewNotificationSender(config, rpcclient.WithLocalSendMsg(s.SendMsg))
s.addInterceptorHandler(MessageHasReadEnabled) s.addInterceptorHandler(MessageHasReadEnabled)
msg.RegisterMsgServer(server, s) msg.RegisterMsgServer(server, s)
return nil return nil

@ -21,7 +21,6 @@ import (
"github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/msg"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/unrelation"
) )

@ -17,15 +17,13 @@ package msg
import ( import (
"context" "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/constant"
"github.com/OpenIMSDK/protocol/msg" "github.com/OpenIMSDK/protocol/msg"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
) )
func (m *msgServer) PullMessageBySeqs( 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) { 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 return nil, err
} }
conversationIDs, err := m.ConversationLocalCache.GetConversationIDs(ctx, req.UserID) conversationIDs, err := m.ConversationLocalCache.GetConversationIDs(ctx, req.UserID)

@ -18,22 +18,21 @@ import (
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
"go.mongodb.org/mongo-driver/mongo" "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 { switch {
case msgData.ContentType == constant.HasReadReceipt && msgData.SessionType == constant.SingleChatType: case msgData.ContentType == constant.HasReadReceipt && msgData.SessionType == constant.SingleChatType:
if config.Config.SingleMessageHasReadReceiptEnable { if config.SingleMessageHasReadReceiptEnable {
return true return true
} else { } else {
return false return false
} }
case msgData.ContentType == constant.HasReadReceipt && msgData.SessionType == constant.SuperGroupChatType: case msgData.ContentType == constant.HasReadReceipt && msgData.SessionType == constant.SuperGroupChatType:
if config.Config.GroupMessageHasReadReceiptEnable { if config.GroupMessageHasReadReceiptEnable {
return true return true
} else { } else {
return false return false

@ -25,8 +25,6 @@ import (
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
) )
var ExcludeContentType = []int{constant.HasReadReceipt} var ExcludeContentType = []int{constant.HasReadReceipt}
@ -51,10 +49,10 @@ type MessageRevoked struct {
func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgReq) error { func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgReq) error {
switch data.MsgData.SessionType { switch data.MsgData.SessionType {
case constant.SingleChatType: case constant.SingleChatType:
if len(config.Config.Manager.UserID) > 0 && utils.IsContain(data.MsgData.SendID, config.Config.Manager.UserID) { if len(m.config.Manager.UserID) > 0 && utils.IsContain(data.MsgData.SendID, m.config.Manager.UserID) {
return nil return nil
} }
if utils.IsContain(data.MsgData.SendID, config.Config.IMAdmin.UserID) { if utils.IsContain(data.MsgData.SendID, m.config.IMAdmin.UserID) {
return nil return nil
} }
if data.MsgData.ContentType <= constant.NotificationEnd && if data.MsgData.ContentType <= constant.NotificationEnd &&
@ -68,7 +66,7 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe
if black { if black {
return errs.ErrBlockedByPeer.Wrap() 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) friend, err := m.friend.IsFriend(ctx, data.MsgData.SendID, data.MsgData.RecvID)
if err != nil { if err != nil {
return err return err
@ -91,10 +89,10 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe
if groupInfo.GroupType == constant.SuperGroup { if groupInfo.GroupType == constant.SuperGroup {
return nil return nil
} }
if len(config.Config.Manager.UserID) > 0 && utils.IsContain(data.MsgData.SendID, config.Config.Manager.UserID) { if len(m.config.Manager.UserID) > 0 && utils.IsContain(data.MsgData.SendID, m.config.Manager.UserID) {
return nil return nil
} }
if utils.IsContain(data.MsgData.SendID, config.Config.IMAdmin.UserID) { if utils.IsContain(data.MsgData.SendID, m.config.IMAdmin.UserID) {
return nil return nil
} }
if data.MsgData.ContentType <= constant.NotificationEnd && if data.MsgData.ContentType <= constant.NotificationEnd &&
@ -159,9 +157,6 @@ func (m *msgServer) encapsulateMsgData(msg *sdkws.MsgData) {
case constant.Custom: case constant.Custom:
fallthrough fallthrough
case constant.Quote: 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: case constant.Revoke:
utils.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, false) utils.SetSwitchFromOptions(msg.Options, constant.IsUnreadCount, false)
utils.SetSwitchFromOptions(msg.Options, constant.IsOfflinePush, false) utils.SetSwitchFromOptions(msg.Options, constant.IsOfflinePush, false)

@ -25,7 +25,6 @@ import (
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
utils2 "github.com/OpenIMSDK/tools/utils" utils2 "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/authverify" "github.com/openimsdk/open-im-server/v3/pkg/authverify"
relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" relationtb "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
) )
@ -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) { 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 return nil, err
} }
userID := "" 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) { 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 return nil, err
} }
var ( var (

@ -23,18 +23,13 @@ import (
"strconv" "strconv"
"time" "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/protocol/third"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/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/s3/cont"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "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) { func (t *thirdServer) InitiateMultipartUpload(ctx context.Context, req *third.InitiateMultipartUploadReq) (*third.InitiateMultipartUploadResp, error) {
defer log.ZDebug(ctx, "return") 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 return nil, err
} }
expireTime := time.Now().Add(t.defaultExpire) 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) { func (t *thirdServer) CompleteMultipartUpload(ctx context.Context, req *third.CompleteMultipartUploadReq) (*third.CompleteMultipartUploadResp, error) {
defer log.ZDebug(ctx, "return") 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 return nil, err
} }
result, err := t.s3dataBase.CompleteMultipartUpload(ctx, req.UploadID, req.Parts) 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 { if req.Size <= 0 {
return nil, errs.ErrArgs.Wrap("size must be greater than 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 return nil, err
} }
var duration time.Duration var duration time.Duration
opUserID := mcontext.GetOpUserID(ctx) opUserID := mcontext.GetOpUserID(ctx)
var key string var key string
if authverify.IsManagerUserID(opUserID) { if t.IsManagerUserID(opUserID) {
if req.Millisecond <= 0 { if req.Millisecond <= 0 {
duration = time.Minute * 10 duration = time.Minute * 10
} else { } else {
@ -214,7 +209,7 @@ func (t *thirdServer) InitiateFormData(ctx context.Context, req *third.InitiateF
} }
uid, err := uuid.NewRandom() uid, err := uuid.NewRandom()
if err != nil { if err != nil {
return nil, err return nil, errs.Wrap(err, "uuid NewRandom failed")
} }
if key == "" { if key == "" {
date := time.Now().Format("20060102") date := time.Now().Format("20060102")
@ -229,7 +224,7 @@ func (t *thirdServer) InitiateFormData(ctx context.Context, req *third.InitiateF
} }
mateData, err := json.Marshal(&mate) mateData, err := json.Marshal(&mate)
if err != nil { 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) resp, err := t.s3dataBase.FormData(ctx, key, req.Size, req.ContentType, duration)
if err != nil { 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 { if err := json.Unmarshal(data, &mate); err != nil {
return nil, errs.ErrArgs.Wrap("invalid id " + err.Error()) 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 return nil, err
} }
info, err := t.s3dataBase.StatObject(ctx, mate.Key) info, err := t.s3dataBase.StatObject(ctx, mate.Key)

@ -17,66 +17,63 @@ package third
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/OpenIMSDK/tools/errs"
"net/url" "net/url"
"time" "time"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/s3/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/protocol/third"
"github.com/OpenIMSDK/tools/discoveryregistry" "github.com/OpenIMSDK/tools/discoveryregistry"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/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" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"google.golang.org/grpc"
) )
func Start(client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error { func Start(config *config.GlobalConfig, client discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
mongo, err := unrelation.NewMongo() mongo, err := unrelation.NewMongo(config)
if err != nil { if err != nil {
return err return err
} }
logdb, err := mgo.NewLogMongo(mongo.GetDatabase()) logdb, err := mgo.NewLogMongo(mongo.GetDatabase(config.Mongo.Database))
if err != nil { if err != nil {
return err return err
} }
s3db, err := mgo.NewS3Mongo(mongo.GetDatabase()) s3db, err := mgo.NewS3Mongo(mongo.GetDatabase(config.Mongo.Database))
if err != nil { if err != nil {
return err return err
} }
apiURL := config.Config.Object.ApiURL apiURL := config.Object.ApiURL
if 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 return err
} }
if apiURL[len(apiURL)-1] != '/' { if apiURL[len(apiURL)-1] != '/' {
apiURL += "/" apiURL += "/"
} }
apiURL += "object/" apiURL += "object/"
rdb, err := cache.NewRedis() rdb, err := cache.NewRedis(config)
if err != nil { if err != nil {
return err return err
} }
// 根据配置文件策略选择 oss 方式 // Select the oss method according to the profile policy
enable := config.Config.Object.Enable enable := config.Object.Enable
var o s3.Interface var o s3.Interface
switch config.Config.Object.Enable { switch enable {
case "minio": case "minio":
o, err = minio.NewMinio(cache.NewMinioCache(rdb)) o, err = minio.NewMinio(cache.NewMinioCache(rdb), minio.Config(config.Object.Minio))
case "cos": case "cos":
o, err = cos.NewCos() o, err = cos.NewCos(cos.Config(config.Object.Cos))
case "oss": case "oss":
o, err = oss.NewOSS() o, err = oss.NewOSS(oss.Config(config.Object.Oss))
default: default:
err = fmt.Errorf("invalid object enable: %s", enable) 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{ third.RegisterThirdServer(server, &thirdServer{
apiURL: apiURL, apiURL: apiURL,
thirdDatabase: controller.NewThirdDatabase(cache.NewMsgCacheModel(rdb), logdb), thirdDatabase: controller.NewThirdDatabase(cache.NewMsgCacheModel(rdb, config), logdb),
userRpcClient: rpcclient.NewUserRpcClient(client), userRpcClient: rpcclient.NewUserRpcClient(client, config),
s3dataBase: controller.NewS3Database(rdb, o, s3db), s3dataBase: controller.NewS3Database(rdb, o, s3db),
defaultExpire: time.Hour * 24 * 7, defaultExpire: time.Hour * 24 * 7,
config: config,
}) })
return nil return nil
} }
@ -99,6 +97,7 @@ type thirdServer struct {
s3dataBase controller.S3Database s3dataBase controller.S3Database
userRpcClient rpcclient.UserRpcClient userRpcClient rpcclient.UserRpcClient
defaultExpire time.Duration defaultExpire time.Duration
config *config.GlobalConfig
} }
func (t *thirdServer) FcmUpdateToken(ctx context.Context, req *third.FcmUpdateTokenReq) (resp *third.FcmUpdateTokenResp, err error) { func (t *thirdServer) FcmUpdateToken(ctx context.Context, req *third.FcmUpdateTokenReq) (resp *third.FcmUpdateTokenResp, err error) {

@ -21,11 +21,10 @@ import (
"strings" "strings"
"unicode/utf8" "unicode/utf8"
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/OpenIMSDK/protocol/third" "github.com/OpenIMSDK/protocol/third"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
) )
func toPbMapArray(m map[string][]string) []*third.KeyValues { func toPbMapArray(m map[string][]string) []*third.KeyValues {
@ -42,7 +41,7 @@ func toPbMapArray(m map[string][]string) []*third.KeyValues {
return res return res
} }
func checkUploadName(ctx context.Context, name string) error { func (t *thirdServer) checkUploadName(ctx context.Context, name string) error {
if name == "" { if name == "" {
return errs.ErrArgs.Wrap("name is empty") return errs.ErrArgs.Wrap("name is empty")
} }
@ -56,7 +55,7 @@ func checkUploadName(ctx context.Context, name string) error {
if opUserID == "" { if opUserID == "" {
return errs.ErrNoPermission.Wrap("opUserID is empty") return errs.ErrNoPermission.Wrap("opUserID is empty")
} }
if !authverify.IsManagerUserID(opUserID) { if !authverify.IsManagerUserID(opUserID, t.config) {
if !strings.HasPrefix(name, opUserID+"/") { if !strings.HasPrefix(name, opUserID+"/") {
return errs.ErrNoPermission.Wrap(fmt.Sprintf("name must start with `%s/`", 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) 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" pbuser "github.com/OpenIMSDK/protocol/user"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct" cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/http" "github.com/openimsdk/open-im-server/v3/pkg/common/http"
) )
func CallbackBeforeUpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInfoReq) error { func CallbackBeforeUpdateUserInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UpdateUserInfoReq) error {
if !config.Config.Callback.CallbackBeforeUpdateUserInfo.Enable { if !globalConfig.Callback.CallbackBeforeUpdateUserInfo.Enable {
return nil return nil
} }
cbReq := &cbapi.CallbackBeforeUpdateUserInfoReq{ cbReq := &cbapi.CallbackBeforeUpdateUserInfoReq{
@ -36,7 +35,7 @@ func CallbackBeforeUpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInf
Nickname: &req.UserInfo.Nickname, Nickname: &req.UserInfo.Nickname,
} }
resp := &cbapi.CallbackBeforeUpdateUserInfoResp{} resp := &cbapi.CallbackBeforeUpdateUserInfoResp{}
if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, cbReq, resp, config.Config.Callback.CallbackBeforeUpdateUserInfo); err != nil { if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, cbReq, resp, globalConfig.Callback.CallbackBeforeUpdateUserInfo); err != nil {
return err return err
} }
utils.NotNilReplace(&req.UserInfo.FaceURL, resp.FaceURL) 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) utils.NotNilReplace(&req.UserInfo.Nickname, resp.Nickname)
return nil return nil
} }
func CallbackAfterUpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInfoReq) error { func CallbackAfterUpdateUserInfo(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UpdateUserInfoReq) error {
if !config.Config.Callback.CallbackAfterUpdateUserInfo.Enable { if !globalConfig.Callback.CallbackAfterUpdateUserInfo.Enable {
return nil return nil
} }
cbReq := &cbapi.CallbackAfterUpdateUserInfoReq{ cbReq := &cbapi.CallbackAfterUpdateUserInfoReq{
@ -55,13 +54,13 @@ func CallbackAfterUpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInfo
Nickname: req.UserInfo.Nickname, Nickname: req.UserInfo.Nickname,
} }
resp := &cbapi.CallbackAfterUpdateUserInfoResp{} 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 err
} }
return nil return nil
} }
func CallbackBeforeUpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUserInfoExReq) error { func CallbackBeforeUpdateUserInfoEx(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UpdateUserInfoExReq) error {
if !config.Config.Callback.CallbackBeforeUpdateUserInfoEx.Enable { if !globalConfig.Callback.CallbackBeforeUpdateUserInfoEx.Enable {
return nil return nil
} }
cbReq := &cbapi.CallbackBeforeUpdateUserInfoExReq{ cbReq := &cbapi.CallbackBeforeUpdateUserInfoExReq{
@ -71,7 +70,7 @@ func CallbackBeforeUpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUserI
Nickname: req.UserInfo.Nickname, Nickname: req.UserInfo.Nickname,
} }
resp := &cbapi.CallbackBeforeUpdateUserInfoExResp{} 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 return err
} }
utils.NotNilReplace(req.UserInfo.FaceURL, resp.FaceURL) 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) utils.NotNilReplace(req.UserInfo.Nickname, resp.Nickname)
return nil return nil
} }
func CallbackAfterUpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUserInfoExReq) error { func CallbackAfterUpdateUserInfoEx(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UpdateUserInfoExReq) error {
if !config.Config.Callback.CallbackAfterUpdateUserInfoEx.Enable { if !globalConfig.Callback.CallbackAfterUpdateUserInfoEx.Enable {
return nil return nil
} }
cbReq := &cbapi.CallbackAfterUpdateUserInfoExReq{ cbReq := &cbapi.CallbackAfterUpdateUserInfoExReq{
@ -90,14 +89,14 @@ func CallbackAfterUpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUserIn
Nickname: req.UserInfo.Nickname, Nickname: req.UserInfo.Nickname,
} }
resp := &cbapi.CallbackAfterUpdateUserInfoExResp{} 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 err
} }
return nil return nil
} }
func CallbackBeforeUserRegister(ctx context.Context, req *pbuser.UserRegisterReq) error { func CallbackBeforeUserRegister(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UserRegisterReq) error {
if !config.Config.Callback.CallbackBeforeUserRegister.Enable { if !globalConfig.Callback.CallbackBeforeUserRegister.Enable {
return nil return nil
} }
cbReq := &cbapi.CallbackBeforeUserRegisterReq{ cbReq := &cbapi.CallbackBeforeUserRegisterReq{
@ -107,7 +106,7 @@ func CallbackBeforeUserRegister(ctx context.Context, req *pbuser.UserRegisterReq
} }
resp := &cbapi.CallbackBeforeUserRegisterResp{} 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 return err
} }
if len(resp.Users) != 0 { if len(resp.Users) != 0 {
@ -116,8 +115,8 @@ func CallbackBeforeUserRegister(ctx context.Context, req *pbuser.UserRegisterReq
return nil return nil
} }
func CallbackAfterUserRegister(ctx context.Context, req *pbuser.UserRegisterReq) error { func CallbackAfterUserRegister(ctx context.Context, globalConfig *config.GlobalConfig, req *pbuser.UserRegisterReq) error {
if !config.Config.Callback.CallbackAfterUserRegister.Enable { if !globalConfig.Callback.CallbackAfterUserRegister.Enable {
return nil return nil
} }
cbReq := &cbapi.CallbackAfterUserRegisterReq{ cbReq := &cbapi.CallbackAfterUserRegisterReq{
@ -127,7 +126,7 @@ func CallbackAfterUserRegister(ctx context.Context, req *pbuser.UserRegisterReq)
} }
resp := &cbapi.CallbackAfterUserRegisterResp{} 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 err
} }
return nil return nil

@ -16,39 +16,31 @@ package user
import ( import (
"context" "context"
"errors" "fmt"
"math/rand" "math/rand"
"strings" "strings"
"time" "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/constant"
"github.com/OpenIMSDK/protocol/sdkws" "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/errs"
"github.com/OpenIMSDK/tools/log" "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/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/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/convert" "github.com/openimsdk/open-im-server/v3/pkg/common/convert"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/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" 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"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "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" "google.golang.org/grpc"
) )
@ -59,6 +51,7 @@ type userServer struct {
friendRpcClient *rpcclient.FriendRpcClient friendRpcClient *rpcclient.FriendRpcClient
groupRpcClient *rpcclient.GroupRpcClient groupRpcClient *rpcclient.GroupRpcClient
RegisterCenter registry.SvcDiscoveryRegistry RegisterCenter registry.SvcDiscoveryRegistry
config *config.GlobalConfig
} }
func (s *userServer) GetGroupOnlineUser(ctx context.Context, req *pbuser.GetGroupOnlineUserReq) (*pbuser.GetGroupOnlineUserResp, error) { 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") panic("implement me")
} }
func Start(client registry.SvcDiscoveryRegistry, server *grpc.Server) error { func Start(config *config.GlobalConfig, client registry.SvcDiscoveryRegistry, server *grpc.Server) error {
rdb, err := cache.NewRedis() rdb, err := cache.NewRedis(config)
if err != nil { if err != nil {
return err return err
} }
mongo, err := unrelation.NewMongo() mongo, err := unrelation.NewMongo(config)
if err != nil { if err != nil {
return err return err
} }
users := make([]*tablerelation.UserModel, 0) users := make([]*tablerelation.UserModel, 0)
if len(config.Config.IMAdmin.UserID) != len(config.Config.IMAdmin.Nickname) { if len(config.IMAdmin.UserID) != len(config.IMAdmin.Nickname) {
return errors.New("len(config.Config.AppNotificationAdmin.AppManagerUid) != len(config.Config.AppNotificationAdmin.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 { for k, v := range config.IMAdmin.UserID {
users = append(users, &tablerelation.UserModel{UserID: v, Nickname: config.Config.IMAdmin.Nickname[k], AppMangerLevel: constant.AppNotificationAdmin}) 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 { if err != nil {
return err return err
} }
cache := cache.NewUserCacheRedis(rdb, userDB, cache.GetDefaultOpt()) cache := cache.NewUserCacheRedis(rdb, userDB, cache.GetDefaultOpt())
userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase()) userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase(config.Mongo.Database))
database := controller.NewUserDatabase(userDB, cache, tx.NewMongo(mongo.GetClient()), userMongoDB) database := controller.NewUserDatabase(userDB, cache, tx.NewMongo(mongo.GetClient()), userMongoDB)
friendRpcClient := rpcclient.NewFriendRpcClient(client) friendRpcClient := rpcclient.NewFriendRpcClient(client, config)
groupRpcClient := rpcclient.NewGroupRpcClient(client) groupRpcClient := rpcclient.NewGroupRpcClient(client, config)
msgRpcClient := rpcclient.NewMessageRpcClient(client) msgRpcClient := rpcclient.NewMessageRpcClient(client, config)
u := &userServer{ u := &userServer{
UserDatabase: database, UserDatabase: database,
RegisterCenter: client, RegisterCenter: client,
friendRpcClient: &friendRpcClient, friendRpcClient: &friendRpcClient,
groupRpcClient: &groupRpcClient, groupRpcClient: &groupRpcClient,
friendNotificationSender: notification.NewFriendNotificationSender(&msgRpcClient, notification.WithDBFunc(database.FindWithError)), friendNotificationSender: notification.NewFriendNotificationSender(config, &msgRpcClient, notification.WithDBFunc(database.FindWithError)),
userNotificationSender: notification.NewUserNotificationSender(&msgRpcClient, notification.WithUserFunc(database.FindWithError)), userNotificationSender: notification.NewUserNotificationSender(config, &msgRpcClient, notification.WithUserFunc(database.FindWithError)),
config: config,
} }
pbuser.RegisterUserServer(server, u) pbuser.RegisterUserServer(server, u)
return u.UserDatabase.InitOnce(context.Background(), users) return u.UserDatabase.InitOnce(context.Background(), users)
@ -111,19 +105,16 @@ func (s *userServer) GetDesignateUsers(ctx context.Context, req *pbuser.GetDesig
return nil, err return nil, err
} }
resp.UsersInfo = convert.UsersDB2Pb(users) resp.UsersInfo = convert.UsersDB2Pb(users)
if err != nil {
return nil, err
}
return resp, nil return resp, nil
} }
func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInfoReq) (resp *pbuser.UpdateUserInfoResp, err error) { func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInfoReq) (resp *pbuser.UpdateUserInfoResp, err error) {
resp = &pbuser.UpdateUserInfoResp{} resp = &pbuser.UpdateUserInfoResp{}
err = authverify.CheckAccessV3(ctx, req.UserInfo.UserID) err = authverify.CheckAccessV3(ctx, req.UserInfo.UserID, s.config)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := CallbackBeforeUpdateUserInfo(ctx, req); err != nil { if err := CallbackBeforeUpdateUserInfo(ctx, s.config, req); err != nil {
return nil, err return nil, err
} }
data := convert.UserPb2DBMap(req.UserInfo) data := convert.UserPb2DBMap(req.UserInfo)
@ -136,29 +127,29 @@ func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserI
return nil, err return nil, err
} }
if req.UserInfo.Nickname != "" || req.UserInfo.FaceURL != "" { if req.UserInfo.Nickname != "" || req.UserInfo.FaceURL != "" {
if err := s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil { if err = s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil {
log.ZError(ctx, "NotificationUserInfoUpdate", err) return nil, err
} }
} }
for _, friendID := range friends { for _, friendID := range friends {
s.friendNotificationSender.FriendInfoUpdatedNotification(ctx, req.UserInfo.UserID, friendID) s.friendNotificationSender.FriendInfoUpdatedNotification(ctx, req.UserInfo.UserID, friendID)
} }
if err := CallbackAfterUpdateUserInfo(ctx, req); err != nil { if err = CallbackAfterUpdateUserInfo(ctx, s.config, req); err != nil {
return nil, err return nil, err
} }
if err := s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil { if err = s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil {
log.ZError(ctx, "NotificationUserInfoUpdate", err, "userID", req.UserInfo.UserID) return nil, err
} }
return resp, nil return resp, nil
} }
func (s *userServer) UpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUserInfoExReq) (resp *pbuser.UpdateUserInfoExResp, err error) { func (s *userServer) UpdateUserInfoEx(ctx context.Context, req *pbuser.UpdateUserInfoExReq) (resp *pbuser.UpdateUserInfoExResp, err error) {
resp = &pbuser.UpdateUserInfoExResp{} resp = &pbuser.UpdateUserInfoExResp{}
err = authverify.CheckAccessV3(ctx, req.UserInfo.UserID) err = authverify.CheckAccessV3(ctx, req.UserInfo.UserID, s.config)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err = CallbackBeforeUpdateUserInfoEx(ctx, req); err != nil { if err = CallbackBeforeUpdateUserInfoEx(ctx, s.config, req); err != nil {
return nil, err return nil, err
} }
data := convert.UserPb2DBMapEx(req.UserInfo) 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 req.UserInfo.Nickname != nil || req.UserInfo.FaceURL != nil {
if err := s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil { if err := s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil {
log.ZError(ctx, "NotificationUserInfoUpdate", err) return nil, err
} }
} }
for _, friendID := range friends { for _, friendID := range friends {
s.friendNotificationSender.FriendInfoUpdatedNotification(ctx, req.UserInfo.UserID, friendID) s.friendNotificationSender.FriendInfoUpdatedNotification(ctx, req.UserInfo.UserID, friendID)
} }
if err := CallbackAfterUpdateUserInfoEx(ctx, req); err != nil { if err := CallbackAfterUpdateUserInfoEx(ctx, s.config, req); err != nil {
return nil, err return nil, err
} }
if err := s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil { if err := s.groupRpcClient.NotificationUserInfoUpdate(ctx, req.UserInfo.UserID); err != nil {
log.ZError(ctx, "NotificationUserInfoUpdate", err, "userID", req.UserInfo.UserID) return nil, err
} }
return resp, nil return resp, nil
} }
@ -205,7 +196,7 @@ func (s *userServer) AccountCheck(ctx context.Context, req *pbuser.AccountCheckR
if utils.Duplicate(req.CheckUserIDs) { if utils.Duplicate(req.CheckUserIDs) {
return nil, errs.ErrArgs.Wrap("userID repeated") return nil, errs.ErrArgs.Wrap("userID repeated")
} }
err = authverify.CheckAdmin(ctx) err = authverify.CheckAdmin(ctx, s.config)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -252,8 +243,8 @@ func (s *userServer) UserRegister(ctx context.Context, req *pbuser.UserRegisterR
if len(req.Users) == 0 { if len(req.Users) == 0 {
return nil, errs.ErrArgs.Wrap("users is empty") return nil, errs.ErrArgs.Wrap("users is empty")
} }
if req.Secret != config.Config.Secret { if req.Secret != s.config.Secret {
log.ZDebug(ctx, "UserRegister", config.Config.Secret, req.Secret) log.ZDebug(ctx, "UserRegister", s.config.Secret, req.Secret)
return nil, errs.ErrNoPermission.Wrap("secret invalid") return nil, errs.ErrNoPermission.Wrap("secret invalid")
} }
if utils.DuplicateAny(req.Users, func(e *sdkws.UserInfo) string { return e.UserID }) { 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 { if exist {
return nil, errs.ErrRegisteredAlready.Wrap("userID registered already") return nil, errs.ErrRegisteredAlready.Wrap("userID registered already")
} }
if err := CallbackBeforeUserRegister(ctx, req); err != nil { if err := CallbackBeforeUserRegister(ctx, s.config, req); err != nil {
return nil, err return nil, err
} }
now := time.Now() now := time.Now()
@ -296,7 +287,7 @@ func (s *userServer) UserRegister(ctx context.Context, req *pbuser.UserRegisterR
return nil, err return nil, err
} }
if err := CallbackAfterUserRegister(ctx, req); err != nil { if err := CallbackAfterUserRegister(ctx, s.config, req); err != nil {
return nil, err return nil, err
} }
return resp, nil return resp, nil
@ -391,7 +382,7 @@ func (s *userServer) GetSubscribeUsersStatus(ctx context.Context,
// ProcessUserCommandAdd user general function add. // ProcessUserCommandAdd user general function add.
func (s *userServer) ProcessUserCommandAdd(ctx context.Context, req *pbuser.ProcessUserCommandAddReq) (*pbuser.ProcessUserCommandAddResp, error) { 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 { if err != nil {
return nil, err return nil, err
} }
@ -422,7 +413,7 @@ func (s *userServer) ProcessUserCommandAdd(ctx context.Context, req *pbuser.Proc
// ProcessUserCommandDelete user general function delete. // ProcessUserCommandDelete user general function delete.
func (s *userServer) ProcessUserCommandDelete(ctx context.Context, req *pbuser.ProcessUserCommandDeleteReq) (*pbuser.ProcessUserCommandDeleteResp, error) { 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 { if err != nil {
return nil, err return nil, err
} }
@ -445,7 +436,7 @@ func (s *userServer) ProcessUserCommandDelete(ctx context.Context, req *pbuser.P
// ProcessUserCommandUpdate user general function update. // ProcessUserCommandUpdate user general function update.
func (s *userServer) ProcessUserCommandUpdate(ctx context.Context, req *pbuser.ProcessUserCommandUpdateReq) (*pbuser.ProcessUserCommandUpdateResp, error) { 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 { if err != nil {
return nil, err 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) { 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 { if err != nil {
return nil, err 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) { 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 { if err != nil {
return nil, err 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) { 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 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) { 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 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) { func (s *userServer) SearchNotificationAccount(ctx context.Context, req *pbuser.SearchNotificationAccountReq) (*pbuser.SearchNotificationAccountResp, error) {
// Check if user is an admin // 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 return nil, err
} }
@ -679,7 +670,7 @@ func (s *userServer) userModelToResp(users []*relation.UserModel, pagination pag
accounts := make([]*pbuser.NotificationAccountInfo, 0) accounts := make([]*pbuser.NotificationAccountInfo, 0)
var total int64 var total int64
for _, v := range users { 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{ temp := &pbuser.NotificationAccountInfo{
UserID: v.UserID, UserID: v.UserID,
FaceURL: v.FaceURL, FaceURL: v.FaceURL,

@ -20,11 +20,9 @@ import (
"time" "time"
"github.com/OpenIMSDK/protocol/sdkws" "github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/table/relation"
) )
@ -58,9 +56,9 @@ import (
// continue // continue
// } // }
// if len(seqs) > 0 { // 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 { // != 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 // continue
// } // }
// if err := c.msgNotificationSender.UserDeleteMsgsNotification(ctx, conversation.OwnerUserID, conversation.ConversationID, seqs); err != nil { // if err := c.msgNotificationSender.UserDeleteMsgsNotification(ctx, conversation.OwnerUserID, conversation.ConversationID, seqs); err != nil {
@ -139,8 +137,8 @@ func (c *MsgTool) ConversationsDestructMsgs() {
continue continue
} }
if len(seqs) > 0 { if len(seqs) > 0 {
if err := c.conversationDatabase.UpdateUsersConversationFiled(ctx, []string{conversation.OwnerUserID}, conversation.ConversationID, map[string]any{"latest_msg_destruct_time": now}); err != nil { if err := c.conversationDatabase.UpdateUsersConversationField(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) log.ZError(ctx, "updateUsersConversationField failed", err, "conversationID", conversation.ConversationID, "ownerUserID", conversation.OwnerUserID)
continue continue
} }
if err := c.msgNotificationSender.UserDeleteMsgsNotification(ctx, conversation.OwnerUserID, conversation.ConversationID, seqs); err != nil { if err := c.msgNotificationSender.UserDeleteMsgsNotification(ctx, conversation.OwnerUserID, conversation.ConversationID, seqs); err != nil {

@ -23,41 +23,39 @@ import (
"time" "time"
"github.com/OpenIMSDK/tools/errs" "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/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/redis/go-redis/v9"
"github.com/robfig/cron/v3"
) )
func StartTask() error { func StartTask(config *config.GlobalConfig) error {
fmt.Println("cron task start, config", config.Config.ChatRecordsClearTime) fmt.Println("cron task start, config", config.ChatRecordsClearTime)
msgTool, err := InitMsgTool() msgTool, err := InitMsgTool(config)
if err != nil { if err != nil {
return err return err
} }
msgTool.convertTools() msgTool.convertTools()
rdb, err := cache.NewRedis() rdb, err := cache.NewRedis(config)
if err != nil { if err != nil {
return err return err
} }
// register cron tasks // register cron tasks
var crontab = cron.New() var crontab = cron.New()
fmt.Println("start chatRecordsClearTime cron task", "cron config", config.Config.ChatRecordsClearTime) fmt.Printf("Start chatRecordsClearTime cron task, cron config: %s\n", config.ChatRecordsClearTime)
_, err = crontab.AddFunc(config.Config.ChatRecordsClearTime, cronWrapFunc(rdb, "cron_clear_msg_and_fix_seq", msgTool.AllConversationClearMsgAndFixSeq)) _, err = crontab.AddFunc(config.ChatRecordsClearTime, cronWrapFunc(config, rdb, "cron_clear_msg_and_fix_seq", msgTool.AllConversationClearMsgAndFixSeq))
if err != nil { if err != nil {
return errs.Wrap(err) return errs.Wrap(err)
} }
fmt.Println("start msgDestruct cron task", "cron config", config.Config.MsgDestructTime) fmt.Printf("Start msgDestruct cron task, cron config: %s\n", config.MsgDestructTime)
_, err = crontab.AddFunc(config.Config.MsgDestructTime, cronWrapFunc(rdb, "cron_conversations_destruct_msgs", msgTool.ConversationsDestructMsgs)) _, err = crontab.AddFunc(config.MsgDestructTime, cronWrapFunc(config, rdb, "cron_conversations_destruct_msgs", msgTool.ConversationsDestructMsgs))
if err != nil { if err != nil {
return errs.Wrap(err) return errs.Wrap(err, "cron_conversations_destruct_msgs")
} }
// start crontab // start crontab
@ -93,8 +91,8 @@ func netlock(rdb redis.UniversalClient, key string, ttl time.Duration) bool {
return ok return ok
} }
func cronWrapFunc(rdb redis.UniversalClient, key string, fn func()) func() { func cronWrapFunc(config *config.GlobalConfig, rdb redis.UniversalClient, key string, fn func()) func() {
enableCronLocker := config.Config.EnableCronLocker enableCronLocker := config.EnableCronLocker
return func() { return func() {
// if don't enable cron-locker, call fn directly. // if don't enable cron-locker, call fn directly.
if !enableCronLocker { if !enableCronLocker {

@ -15,12 +15,17 @@
package tools package tools
import ( import (
"flag"
"fmt" "fmt"
"math/rand" "math/rand"
"os"
"sync" "sync"
"testing" "testing"
"time" "time"
"github.com/OpenIMSDK/tools/errs"
"gopkg.in/yaml.v3"
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
"github.com/robfig/cron/v3" "github.com/robfig/cron/v3"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -61,7 +66,7 @@ func TestCronWrapFunc(t *testing.T) {
start := time.Now() start := time.Now()
key := fmt.Sprintf("cron-%v", rand.Int31()) key := fmt.Sprintf("cron-%v", rand.Int31())
crontab := cron.New(cron.WithSeconds()) crontab := cron.New(cron.WithSeconds())
crontab.AddFunc("*/1 * * * * *", cronWrapFunc(rdb, key, cb)) crontab.AddFunc("*/1 * * * * *", cronWrapFunc(config.NewGlobalConfig(), rdb, key, cb))
crontab.Start() crontab.Start()
<-done <-done
@ -71,7 +76,11 @@ func TestCronWrapFunc(t *testing.T) {
} }
func TestCronWrapFuncWithNetlock(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{}) rdb := redis.NewClient(&redis.Options{})
defer rdb.Close() defer rdb.Close()
@ -80,10 +89,10 @@ func TestCronWrapFuncWithNetlock(t *testing.T) {
crontab := cron.New(cron.WithSeconds()) crontab := cron.New(cron.WithSeconds())
key := fmt.Sprintf("cron-%v", rand.Int31()) key := fmt.Sprintf("cron-%v", rand.Int31())
crontab.AddFunc("*/1 * * * * *", cronWrapFunc(rdb, key, func() { crontab.AddFunc("*/1 * * * * *", cronWrapFunc(conf, rdb, key, func() {
done <- "host1" done <- "host1"
})) }))
crontab.AddFunc("*/1 * * * * *", cronWrapFunc(rdb, key, func() { crontab.AddFunc("*/1 * * * * *", cronWrapFunc(conf, rdb, key, func() {
done <- "host2" done <- "host2"
})) }))
crontab.Start() crontab.Start()
@ -94,3 +103,22 @@ func TestCronWrapFuncWithNetlock(t *testing.T) {
crontab.Stop() 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" "context"
"fmt" "fmt"
"math" "math"
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/tx"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
"github.com/redis/go-redis/v9"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
"math/rand" "math/rand"
"github.com/OpenIMSDK/protocol/sdkws"
"github.com/OpenIMSDK/tools/errs" "github.com/OpenIMSDK/tools/errs"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/OpenIMSDK/tools/mw" "github.com/OpenIMSDK/tools/mw"
"github.com/OpenIMSDK/tools/tx"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache" "github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/controller" "github.com/openimsdk/open-im-server/v3/pkg/common/db/controller"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/mgo"
"github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation" "github.com/openimsdk/open-im-server/v3/pkg/common/db/unrelation"
kdisc "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification" "github.com/openimsdk/open-im-server/v3/pkg/rpcclient/notification"
"github.com/redis/go-redis/v9"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
) )
type MsgTool struct { type MsgTool struct {
@ -52,10 +46,12 @@ type MsgTool struct {
userDatabase controller.UserDatabase userDatabase controller.UserDatabase
groupDatabase controller.GroupDatabase groupDatabase controller.GroupDatabase
msgNotificationSender *notification.MsgNotificationSender msgNotificationSender *notification.MsgNotificationSender
Config *config.GlobalConfig
} }
func NewMsgTool(msgDatabase controller.CommonMsgDatabase, userDatabase controller.UserDatabase, 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 { ) *MsgTool {
return &MsgTool{ return &MsgTool{
msgDatabase: msgDatabase, msgDatabase: msgDatabase,
@ -63,32 +59,33 @@ func NewMsgTool(msgDatabase controller.CommonMsgDatabase, userDatabase controlle
groupDatabase: groupDatabase, groupDatabase: groupDatabase,
conversationDatabase: conversationDatabase, conversationDatabase: conversationDatabase,
msgNotificationSender: msgNotificationSender, msgNotificationSender: msgNotificationSender,
Config: config,
} }
} }
func InitMsgTool() (*MsgTool, error) { func InitMsgTool(config *config.GlobalConfig) (*MsgTool, error) {
rdb, err := cache.NewRedis() rdb, err := cache.NewRedis(config)
if err != nil { if err != nil {
return nil, err return nil, err
} }
mongo, err := unrelation.NewMongo() mongo, err := unrelation.NewMongo(config)
if err != nil { if err != nil {
return nil, err return nil, err
} }
discov, err := kdisc.NewDiscoveryRegister(config.Config.Envs.Discovery) discov, err := kdisc.NewDiscoveryRegister(config)
if err != nil { if err != nil {
return nil, err return nil, err
} }
discov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) 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 { if err != nil {
return nil, err return nil, err
} }
msgDatabase, err := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase()) msgDatabase, err := controller.InitCommonMsgDatabase(rdb, mongo.GetDatabase(config.Mongo.Database), config)
if err != nil { if err != nil {
return nil, err return nil, err
} }
userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase()) userMongoDB := unrelation.NewUserMongoDriver(mongo.GetDatabase(config.Mongo.Database))
ctxTx := tx.NewMongo(mongo.GetClient()) ctxTx := tx.NewMongo(mongo.GetClient())
userDatabase := controller.NewUserDatabase( userDatabase := controller.NewUserDatabase(
userDB, userDB,
@ -96,19 +93,19 @@ func InitMsgTool() (*MsgTool, error) {
ctxTx, ctxTx,
userMongoDB, userMongoDB,
) )
groupDB, err := mgo.NewGroupMongo(mongo.GetDatabase()) groupDB, err := mgo.NewGroupMongo(mongo.GetDatabase(config.Mongo.Database))
if err != nil { if err != nil {
return nil, err return nil, err
} }
groupMemberDB, err := mgo.NewGroupMember(mongo.GetDatabase()) groupMemberDB, err := mgo.NewGroupMember(mongo.GetDatabase(config.Mongo.Database))
if err != nil { if err != nil {
return nil, err return nil, err
} }
groupRequestDB, err := mgo.NewGroupRequestMgo(mongo.GetDatabase()) groupRequestDB, err := mgo.NewGroupRequestMgo(mongo.GetDatabase(config.Mongo.Database))
if err != nil { if err != nil {
return nil, err return nil, err
} }
conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase()) conversationDB, err := mgo.NewConversationMongo(mongo.GetDatabase(config.Mongo.Database))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -118,9 +115,9 @@ func InitMsgTool() (*MsgTool, error) {
cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB), cache.NewConversationRedis(rdb, cache.GetDefaultOpt(), conversationDB),
ctxTx, ctxTx,
) )
msgRpcClient := rpcclient.NewMessageRpcClient(discov) msgRpcClient := rpcclient.NewMessageRpcClient(discov, config)
msgNotificationSender := notification.NewMsgNotificationSender(rpcclient.WithRpcClient(&msgRpcClient)) msgNotificationSender := notification.NewMsgNotificationSender(config, rpcclient.WithRpcClient(&msgRpcClient))
msgTool := NewMsgTool(msgDatabase, userDatabase, groupDatabase, conversationDatabase, msgNotificationSender) msgTool := NewMsgTool(msgDatabase, userDatabase, groupDatabase, conversationDatabase, msgNotificationSender, config)
return msgTool, nil return msgTool, nil
} }
@ -182,8 +179,8 @@ func (c *MsgTool) AllConversationClearMsgAndFixSeq() {
func (c *MsgTool) ClearConversationsMsg(ctx context.Context, conversationIDs []string) { func (c *MsgTool) ClearConversationsMsg(ctx context.Context, conversationIDs []string) {
for _, conversationID := range conversationIDs { for _, conversationID := range conversationIDs {
if err := c.msgDatabase.DeleteConversationMsgsAndSetMinSeq(ctx, conversationID, int64(config.Config.RetainChatRecords*24*60*60)); err != nil { 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", config.Config.RetainChatRecords) log.ZError(ctx, "DeleteUserSuperGroupMsgsAndSetMinSeq failed", err, "conversationID", conversationID, "DBRetainChatRecords", c.Config.RetainChatRecords)
} }
if err := c.checkMaxSeq(ctx, conversationID); err != nil { if err := c.checkMaxSeq(ctx, conversationID); err != nil {
log.ZError(ctx, "fixSeq failed", err, "conversationID", conversationID) log.ZError(ctx, "fixSeq failed", err, "conversationID", conversationID)
@ -197,7 +194,8 @@ func (c *MsgTool) checkMaxSeqWithMongo(ctx context.Context, conversationID strin
return err return err
} }
if math.Abs(float64(maxSeqMongo-maxSeqCache)) > 10 { 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 return nil
} }
@ -219,7 +217,6 @@ func (c *MsgTool) checkMaxSeq(ctx context.Context, conversationID string) error
func (c *MsgTool) FixAllSeq(ctx context.Context) error { func (c *MsgTool) FixAllSeq(ctx context.Context) error {
conversationIDs, err := c.conversationDatabase.GetAllConversationIDs(ctx) conversationIDs, err := c.conversationDatabase.GetAllConversationIDs(ctx)
if err != nil { if err != nil {
log.ZError(ctx, "GetAllConversationIDs failed", err)
return err return err
} }
for _, conversationID := range conversationIDs { for _, conversationID := range conversationIDs {

@ -18,7 +18,6 @@ import (
"github.com/OpenIMSDK/protocol/constant" "github.com/OpenIMSDK/protocol/constant"
"github.com/OpenIMSDK/tools/log" "github.com/OpenIMSDK/tools/log"
"github.com/OpenIMSDK/tools/mcontext" "github.com/OpenIMSDK/tools/mcontext"
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor" "github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
) )

@ -67,6 +67,7 @@ type LocationElem struct {
Longitude float64 `mapstructure:"longitude" validate:"required"` Longitude float64 `mapstructure:"longitude" validate:"required"`
Latitude float64 `mapstructure:"latitude" validate:"required"` Latitude float64 `mapstructure:"latitude" validate:"required"`
} }
type CustomElem struct { type CustomElem struct {
Data string `mapstructure:"data" validate:"required"` Data string `mapstructure:"data" validate:"required"`
Description string `mapstructure:"description"` Description string `mapstructure:"description"`

@ -23,64 +23,63 @@ import (
"github.com/OpenIMSDK/tools/tokenverify" "github.com/OpenIMSDK/tools/tokenverify"
"github.com/OpenIMSDK/tools/utils" "github.com/OpenIMSDK/tools/utils"
"github.com/golang-jwt/jwt/v4" "github.com/golang-jwt/jwt/v4"
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "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 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) 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 return nil
} }
if utils.IsContain(opUserID, config.Config.IMAdmin.UserID) { if utils.IsContain(opUserID, config.IMAdmin.UserID) {
return nil return nil
} }
if opUserID == ownerUserID { if opUserID == ownerUserID {
return nil return nil
} }
return errs.ErrNoPermission.Wrap(utils.GetSelfFuncName()) return errs.ErrNoPermission.Wrap("ownerUserID", ownerUserID)
} }
func IsAppManagerUid(ctx context.Context) bool { func IsAppManagerUid(ctx context.Context, config *config.GlobalConfig) bool {
return (len(config.Config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.Manager.UserID)) || return (len(config.Manager.UserID) > 0 && utils.IsContain(mcontext.GetOpUserID(ctx), config.Manager.UserID)) ||
utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) utils.IsContain(mcontext.GetOpUserID(ctx), config.IMAdmin.UserID)
} }
func CheckAdmin(ctx context.Context) error { func CheckAdmin(ctx context.Context, config *config.GlobalConfig) error {
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 nil
} }
if utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) { if utils.IsContain(mcontext.GetOpUserID(ctx), config.IMAdmin.UserID) {
return nil return nil
} }
return errs.ErrNoPermission.Wrap(fmt.Sprintf("user %s is not admin userID", mcontext.GetOpUserID(ctx))) return errs.ErrNoPermission.Wrap(fmt.Sprintf("user %s is not admin userID", mcontext.GetOpUserID(ctx)))
} }
func CheckIMAdmin(ctx context.Context) error { func CheckIMAdmin(ctx context.Context, config *config.GlobalConfig) error {
if utils.IsContain(mcontext.GetOpUserID(ctx), config.Config.IMAdmin.UserID) { if utils.IsContain(mcontext.GetOpUserID(ctx), config.IMAdmin.UserID) {
return nil 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 nil
} }
return errs.ErrNoPermission.Wrap(fmt.Sprintf("user %s is not CheckIMAdmin userID", mcontext.GetOpUserID(ctx))) return errs.ErrNoPermission.Wrap(fmt.Sprintf("user %s is not CheckIMAdmin userID", mcontext.GetOpUserID(ctx)))
} }
func ParseRedisInterfaceToken(redisToken any) (*tokenverify.Claims, error) { func ParseRedisInterfaceToken(redisToken any, secret string) (*tokenverify.Claims, error) {
return tokenverify.GetClaimFromToken(string(redisToken.([]uint8)), Secret()) return tokenverify.GetClaimFromToken(string(redisToken.([]uint8)), Secret(secret))
} }
func IsManagerUserID(opUserID string) bool { func IsManagerUserID(opUserID string, config *config.GlobalConfig) bool {
return (len(config.Config.Manager.UserID) > 0 && utils.IsContain(opUserID, config.Config.Manager.UserID)) || utils.IsContain(opUserID, config.Config.IMAdmin.UserID) 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 { func WsVerifyToken(token, userID, secret string, platformID int) error {
claim, err := tokenverify.GetClaimFromToken(token, Secret()) claim, err := tokenverify.GetClaimFromToken(token, Secret(secret))
if err != nil { if err != nil {
return err return err
} }

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

@ -16,33 +16,42 @@ package cmd
import ( import (
"github.com/OpenIMSDK/protocol/constant" "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" "github.com/spf13/cobra"
config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config"
) )
type ApiCmd struct { type ApiCmd struct {
*RootCmd *RootCmd
initFunc func(config *config.GlobalConfig, port int, promPort int) error
} }
func NewApiCmd() *ApiCmd { func NewApiCmd() *ApiCmd {
ret := &ApiCmd{NewRootCmd("api")} ret := &ApiCmd{RootCmd: NewRootCmd("api"), initFunc: api.Start}
ret.SetRootCmdPt(ret) ret.SetRootCmdPt(ret)
ret.addPreRun()
ret.addRunE()
return ret 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 { 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 { func (a *ApiCmd) GetPortFromConfig(portType string) int {
if portType == constant.FlagPort { if portType == constant.FlagPort {
return config2.Config.Api.OpenImApiPort[0] return a.config.Api.OpenImApiPort[0]
} else if portType == constant.FlagPrometheusPort { } else if portType == constant.FlagPrometheusPort {
return config2.Config.Prometheus.ApiPrometheusPort[0] return a.config.Prometheus.ApiPrometheusPort[0]
} }
return 0 return 0
} }

@ -14,25 +14,35 @@
package cmd 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 { type CronTaskCmd struct {
*RootCmd *RootCmd
initFunc func(config *config.GlobalConfig) error
} }
func NewCronTaskCmd() *CronTaskCmd { func NewCronTaskCmd() *CronTaskCmd {
ret := &CronTaskCmd{NewRootCmd("cronTask", WithCronTaskLogName())} ret := &CronTaskCmd{RootCmd: NewRootCmd("cronTask", WithCronTaskLogName()),
initFunc: tools.StartTask}
ret.addRunE()
ret.SetRootCmdPt(ret) ret.SetRootCmdPt(ret)
return ret return ret
} }
func (c *CronTaskCmd) addRunE(f func() error) { func (c *CronTaskCmd) addRunE() {
c.Command.RunE = func(cmd *cobra.Command, args []string) error { 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 { func (c *CronTaskCmd) Exec() error {
c.addRunE(f)
return c.Execute() 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