Merge branch 'v2.3.0release'

This commit is contained in:
wangchuxiao 2023-01-03 17:01:54 +08:00
commit 7ac790e4d0
95 changed files with 8278 additions and 6272 deletions

View File

@ -163,6 +163,11 @@ func main() {
chatGroup.POST("/batch_send_msg", manage.ManagementBatchSendMsg)
chatGroup.POST("/check_msg_is_send_success", manage.CheckMsgIsSendSuccess)
chatGroup.POST("/set_msg_min_seq", apiChat.SetMsgMinSeq)
chatGroup.POST("/set_message_reaction_extensions", apiChat.SetMessageReactionExtensions)
chatGroup.POST("/get_message_list_reaction_extensions", apiChat.GetMessageListReactionExtensions)
chatGroup.POST("/add_message_reaction_extensions", apiChat.AddMessageReactionExtensions)
chatGroup.POST("/delete_message_reaction_extensions", apiChat.DeleteMessageReactionExtensions)
}
//Conversation
conversationGroup := r.Group("/conversation")
@ -232,7 +237,7 @@ func main() {
if config.Config.Api.ListenIP != "" {
address = config.Config.Api.ListenIP + ":" + strconv.Itoa(*ginPort)
}
fmt.Println("start api server, address: ", address, "OpenIM version: ", constant.CurrentVersion, "\n")
fmt.Println("start api server, address: ", address, ", OpenIM version: ", constant.CurrentVersion)
err := r.Run(address)
if err != nil {
log.Error("", "api run failed ", address, err.Error())

View File

@ -25,6 +25,6 @@ func main() {
address = config.Config.Api.ListenIP + ":" + strconv.Itoa(*ginPort)
}
address = config.Config.CmsApi.ListenIP + ":" + strconv.Itoa(*ginPort)
fmt.Println("start cms api server, address: ", address, "OpenIM version: ", constant.CurrentVersion, "\n")
fmt.Println("start cms api server, address: ", address, ", OpenIM version: ", constant.CurrentVersion, "\n")
router.Run(address)
}

View File

@ -2,10 +2,15 @@ package main
import (
"Open_IM/internal/cron_task"
"flag"
"fmt"
"time"
)
func main() {
fmt.Println("start cronTask")
cronTask.StartCronTask()
var userID = flag.String("userID", "", "userID to clear msg and reset seq")
var workingGroupID = flag.String("workingGroupID", "", "workingGroupID to clear msg and reset seq")
flag.Parse()
fmt.Println(time.Now(), "start cronTask", *userID, *workingGroupID)
cronTask.StartCronTask(*userID, *workingGroupID)
}

View File

@ -70,7 +70,7 @@ func main() {
address = config.Config.Api.ListenIP + ":" + strconv.Itoa(*ginPort)
}
address = config.Config.CmsApi.ListenIP + ":" + strconv.Itoa(*ginPort)
fmt.Println("start demo api server address: ", address, "OpenIM version: ", constant.CurrentVersion, "\n")
fmt.Println("start demo api server address: ", address, ", OpenIM version: ", constant.CurrentVersion, "\n")
go register.OnboardingProcessRoutine()
go register.ImportFriendRoutine()
err := r.Run(address)

View File

@ -21,7 +21,7 @@ func main() {
flag.Parse()
var wg sync.WaitGroup
wg.Add(1)
fmt.Println("start rpc/msg_gateway server, port: ", *rpcPort, *wsPort, *prometheusPort, "OpenIM version: ", constant.CurrentVersion, "\n")
fmt.Println("start rpc/msg_gateway server, port: ", *rpcPort, *wsPort, *prometheusPort, ", OpenIM version: ", constant.CurrentVersion, "\n")
gate.Init(*rpcPort, *wsPort)
gate.Run(*prometheusPort)
wg.Wait()

View File

@ -17,7 +17,7 @@ func main() {
flag.Parse()
log.NewPrivateLog(constant.LogFileName)
logic.Init()
fmt.Println("start msg_transfer server ", "OpenIM version: ", constant.CurrentVersion, "\n")
fmt.Println("start msg_transfer server ", ", OpenIM version: ", constant.CurrentVersion, "\n")
logic.Run(*prometheusPort)
wg.Wait()
}

View File

@ -18,7 +18,7 @@ func main() {
var wg sync.WaitGroup
wg.Add(1)
log.NewPrivateLog(constant.LogFileName)
fmt.Println("start push rpc server, port: ", *rpcPort, "OpenIM version: ", constant.CurrentVersion, "\n")
fmt.Println("start push rpc server, port: ", *rpcPort, ", OpenIM version: ", constant.CurrentVersion, "\n")
logic.Init(*rpcPort)
logic.Run(*prometheusPort)
wg.Wait()

View File

@ -14,7 +14,7 @@ func main() {
rpcPort := flag.Int("port", defaultPorts[0], "rpc listening port")
prometheusPort := flag.Int("prometheus_port", config.Config.Prometheus.AdminCmsPrometheusPort[0], "adminCMSPrometheusPort default listen port")
flag.Parse()
fmt.Println("start cms rpc server, port: ", *rpcPort, "OpenIM version: ", constant.CurrentVersion, "\n")
fmt.Println("start cms rpc server, port: ", *rpcPort, ", OpenIM version: ", constant.CurrentVersion, "\n")
rpcServer := rpcMessageCMS.NewAdminCMSServer(*rpcPort)
go func() {
err := promePkg.StartPromeSrv(*prometheusPort)

View File

@ -14,7 +14,7 @@ func main() {
rpcPort := flag.Int("port", defaultPorts[0], "RpcToken default listen port 10800")
prometheusPort := flag.Int("prometheus_port", config.Config.Prometheus.AuthPrometheusPort[0], "authPrometheusPort default listen port")
flag.Parse()
fmt.Println("start auth rpc server, port: ", *rpcPort, "OpenIM version: ", constant.CurrentVersion, "\n")
fmt.Println("start auth rpc server, port: ", *rpcPort, ", OpenIM version: ", constant.CurrentVersion, "\n")
rpcServer := rpcAuth.NewRpcAuthServer(*rpcPort)
go func() {
err := promePkg.StartPromeSrv(*prometheusPort)

View File

@ -15,7 +15,7 @@ func main() {
rpcPort := flag.Int("port", defaultPorts[0], "RpcToken default listen port 10800")
prometheusPort := flag.Int("prometheus_port", config.Config.Prometheus.CachePrometheusPort[0], "cachePrometheusPort default listen port")
flag.Parse()
fmt.Println("start cache rpc server, port: ", *rpcPort, "OpenIM version: ", constant.CurrentVersion, "\n")
fmt.Println("start cache rpc server, port: ", *rpcPort, ", OpenIM version: ", constant.CurrentVersion, "\n")
rpcServer := rpcCache.NewCacheServer(*rpcPort)
go func() {
err := promePkg.StartPromeSrv(*prometheusPort)

View File

@ -14,7 +14,7 @@ func main() {
rpcPort := flag.Int("port", defaultPorts[0], "RpcConversation default listen port 11300")
prometheusPort := flag.Int("prometheus_port", config.Config.Prometheus.ConversationPrometheusPort[0], "conversationPrometheusPort default listen port")
flag.Parse()
fmt.Println("start conversation rpc server, port: ", *rpcPort, "OpenIM version: ", constant.CurrentVersion, "\n")
fmt.Println("start conversation rpc server, port: ", *rpcPort, ", OpenIM version: ", constant.CurrentVersion, "\n")
rpcServer := rpcConversation.NewRpcConversationServer(*rpcPort)
go func() {
err := promePkg.StartPromeSrv(*prometheusPort)

View File

@ -14,7 +14,7 @@ func main() {
rpcPort := flag.Int("port", defaultPorts[0], "get RpcFriendPort from cmd,default 12000 as port")
prometheusPort := flag.Int("prometheus_port", config.Config.Prometheus.FriendPrometheusPort[0], "friendPrometheusPort default listen port")
flag.Parse()
fmt.Println("start friend rpc server, port: ", *rpcPort, "OpenIM version: ", constant.CurrentVersion, "\n")
fmt.Println("start friend rpc server, port: ", *rpcPort, ", OpenIM version: ", constant.CurrentVersion, "\n")
rpcServer := friend.NewFriendServer(*rpcPort)
go func() {
err := promePkg.StartPromeSrv(*prometheusPort)

View File

@ -14,7 +14,7 @@ func main() {
rpcPort := flag.Int("port", defaultPorts[0], "get RpcGroupPort from cmd,default 16000 as port")
prometheusPort := flag.Int("prometheus_port", config.Config.Prometheus.GroupPrometheusPort[0], "groupPrometheusPort default listen port")
flag.Parse()
fmt.Println("start group rpc server, port: ", *rpcPort, "OpenIM version: ", constant.CurrentVersion, "\n")
fmt.Println("start group rpc server, port: ", *rpcPort, ", OpenIM version: ", constant.CurrentVersion, "\n")
rpcServer := group.NewGroupServer(*rpcPort)
go func() {
err := promePkg.StartPromeSrv(*prometheusPort)

View File

@ -14,7 +14,7 @@ func main() {
rpcPort := flag.Int("port", defaultPorts[0], "rpc listening port")
prometheusPort := flag.Int("prometheus_port", config.Config.Prometheus.MessagePrometheusPort[0], "msgPrometheusPort default listen port")
flag.Parse()
fmt.Println("start msg rpc server, port: ", *rpcPort, "OpenIM version: ", constant.CurrentVersion, "\n")
fmt.Println("start msg rpc server, port: ", *rpcPort, ", OpenIM version: ", constant.CurrentVersion, "\n")
rpcServer := msg.NewRpcChatServer(*rpcPort)
go func() {
err := promePkg.StartPromeSrv(*prometheusPort)

View File

@ -14,7 +14,7 @@ func main() {
rpcPort := flag.Int("port", defaultPorts[0], "rpc listening port")
prometheusPort := flag.Int("prometheus_port", config.Config.Prometheus.OfficePrometheusPort[0], "officePrometheusPort default listen port")
flag.Parse()
fmt.Println("start office rpc server, port: ", *rpcPort, "OpenIM version: ", constant.CurrentVersion, "\n")
fmt.Println("start office rpc server, port: ", *rpcPort, ", OpenIM version: ", constant.CurrentVersion, "\n")
rpcServer := rpc.NewOfficeServer(*rpcPort)
go func() {
err := promePkg.StartPromeSrv(*prometheusPort)

View File

@ -14,7 +14,7 @@ func main() {
rpcPort := flag.Int("port", defaultPorts[0], "get RpcOrganizationPort from cmd,default 11200 as port")
prometheusPort := flag.Int("prometheus_port", config.Config.Prometheus.OrganizationPrometheusPort[0], "organizationPrometheusPort default listen port")
flag.Parse()
fmt.Println("start organization rpc server, port: ", *rpcPort, "OpenIM version: ", constant.CurrentVersion, "\n")
fmt.Println("start organization rpc server, port: ", *rpcPort, ", OpenIM version: ", constant.CurrentVersion, "\n")
rpcServer := organization.NewServer(*rpcPort)
go func() {
err := promePkg.StartPromeSrv(*prometheusPort)

View File

@ -14,7 +14,7 @@ func main() {
rpcPort := flag.Int("port", defaultPorts[0], "rpc listening port")
prometheusPort := flag.Int("prometheus_port", config.Config.Prometheus.UserPrometheusPort[0], "userPrometheusPort default listen port")
flag.Parse()
fmt.Println("start user rpc server, port: ", *rpcPort, "OpenIM version: ", constant.CurrentVersion, "\n")
fmt.Println("start user rpc server, port: ", *rpcPort, ", OpenIM version: ", constant.CurrentVersion, "\n")
rpcServer := user.NewUserServer(*rpcPort)
go func() {
err := promePkg.StartPromeSrv(*prometheusPort)

View File

@ -36,7 +36,7 @@ mongo:
dbPassword: #mongo密码建议先不设置
dbMaxPoolSize: 100
dbRetainChatRecords: 3650 #mongo保存离线消息时间根据需求修改
chatRecordsClearTime: "* * * * *" # 每天凌晨3点清除消息该配置和linux定时任务一样 清理操作建议设置在用户活跃少的时候 # 0 3 * * *
chatRecordsClearTime: "0 3 * * *" # 每天凌晨3点清除消息该配置和linux定时任务一样 清理操作建议设置在用户活跃少的时候 # 0 3 * * *
redis:
dbAddress: [ 127.0.0.1:16379 ] #redis地址 单机时填写一个地址即可使用redis集群时候填写集群中多个节点地址主从地址都可以填写增加容灾能力默认即可
@ -62,12 +62,15 @@ kafka:
ms2pschat:
addr: [ 127.0.0.1:9092 ] #kafka配置默认即可
topic: "ms2ps_chat" #消息push
msgtomodify:
addr: [ 127.0.0.1:9092 ] #kafka配置默认即可
topic: "msg_to_modify"
consumergroupid:
msgToTransfer: mongo
msgToMongo: mongo_ex
msgToMySql: mysql
msgToPush: push
msgToModify: modify
#---------------Internal service configuration---------------------#
@ -341,6 +344,19 @@ callback:
enable: false
callbackTimeOut: 2
callbackFailedContinue: true # 回调超时是否继续
callbackBeforeMemberJoinGroup:
enable: false
callbackTimeOut: 2
callbackFailedContinue: true # 回调超时是否继续
callbackBeforeSetGroupMemberInfo:
enable: false
callbackTimeOut: 2
callbackFailedContinue: true # 回调超时是否继续
callbackSetMessageReactionExtensions:
enable: false
callbackTimeOut: 2
callbackFailedContinue: true # 回调超时是否继续
notification:
groupCreated:
@ -661,6 +677,19 @@ notification:
defaultTips:
tips: "Remove a blocked user"
friendInfoUpdated:
conversation:
reliabilityLevel: 2
unreadCount: false
offlinePush:
switch: true
title: "friend info updated"
desc: "friend info updated"
ext: "friend info updated"
defaultTips:
tips: "friend info updated"
#####################user#########################
userInfoUpdated:
conversation:

View File

@ -115,7 +115,7 @@ services:
open_im_server:
image: openim/open_im_server:v2.3.6
image: openim/open_im_server:v2.3.7
container_name: open_im_server
volumes:
- ./logs:/Open-IM-Server/logs
@ -139,7 +139,7 @@ services:
max-file: "2"
open_im_enterprise:
image: openim/open_im_enterprise:v1.0.2
image: openim/open_im_enterprise:v1.0.3
container_name: open_im_enterprise
volumes:
- ./logs:/Open-IM-Enterprise/logs

1
go.mod
View File

@ -29,7 +29,6 @@ require (
github.com/gorilla/websocket v1.4.2
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
github.com/jinzhu/copier v0.3.4
github.com/jinzhu/gorm v1.9.16
github.com/jonboulle/clockwork v0.2.2 // indirect
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
github.com/lestrrat-go/strftime v1.0.4 // indirect

2
go.sum
View File

@ -368,8 +368,6 @@ github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZ
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
github.com/jinzhu/copier v0.3.4 h1:mfU6jI9PtCeUjkjQ322dlff9ELjGDu975C2p/nrubVI=
github.com/jinzhu/copier v0.3.4/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=

View File

@ -199,7 +199,6 @@ func ForceLogout(c *gin.Context) {
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": errMsg})
return
}
req := &rpc.ForceLogoutReq{}
utils.CopyStructFields(req, &params)

View File

@ -9,7 +9,6 @@ import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
)
func SetClientInitConfig(c *gin.Context) {
@ -62,11 +61,10 @@ func GetClientInitConfig(c *gin.Context) {
}
config, err := imdb.GetClientInitConfig()
if err != nil {
if !gorm.IsRecordNotFoundError(err) {
log.NewError(req.OperationID, utils.GetSelfFuncName(), err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": err.Error()})
return
}
log.NewError(req.OperationID, utils.GetSelfFuncName(), err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": err.Error()})
return
}
resp.Data.DiscoverPageURL = config.DiscoverPageURL
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp ", resp)

View File

@ -52,6 +52,10 @@ func newUserSendMsgReq(params *api.ManagementSendMsgReq) *pbChat.SendMsgReq {
fallthrough
case constant.File:
fallthrough
case constant.CustomNotTriggerConversation:
fallthrough
case constant.CustomOnlineOnly:
fallthrough
case constant.AdvancedRevoke:
newContent = utils.StructToJsonString(params.Content)
case constant.Revoke:

View File

@ -0,0 +1,203 @@
package msg
import (
api "Open_IM/pkg/base_info"
"Open_IM/pkg/common/config"
"Open_IM/pkg/common/constant"
"Open_IM/pkg/common/log"
"Open_IM/pkg/common/token_verify"
"Open_IM/pkg/grpc-etcdv3/getcdv3"
rpc "Open_IM/pkg/proto/msg"
"Open_IM/pkg/utils"
"context"
"github.com/gin-gonic/gin"
"net/http"
"strings"
)
func SetMessageReactionExtensions(c *gin.Context) {
var (
req api.SetMessageReactionExtensionsCallbackReq
resp api.SetMessageReactionExtensionsCallbackResp
reqPb rpc.SetMessageReactionExtensionsReq
)
if err := c.BindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()})
return
}
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req:", req)
if err := utils.CopyStructFields(&reqPb, &req); err != nil {
log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields", err.Error())
}
var ok bool
var errInfo string
ok, reqPb.OpUserID, errInfo = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID)
if !ok {
errMsg := req.OperationID + " " + "GetUserIDFromToken failed " + errInfo + " token:" + c.Request.Header.Get("token")
log.NewError(req.OperationID, errMsg)
c.JSON(http.StatusBadRequest, gin.H{"errCode": 500, "errMsg": errMsg})
return
}
grpcConn := getcdv3.GetDefaultConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImMsgName, req.OperationID)
if grpcConn == nil {
errMsg := req.OperationID + " getcdv3.GetDefaultConn == nil"
log.NewError(req.OperationID, errMsg)
c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg})
return
}
msgClient := rpc.NewMsgClient(grpcConn)
respPb, err := msgClient.SetMessageReactionExtensions(context.Background(), &reqPb)
if err != nil {
log.NewError(req.OperationID, utils.GetSelfFuncName(), "DelMsgList failed", err.Error(), reqPb)
c.JSON(http.StatusInternalServerError, gin.H{"errCode": constant.ErrServer.ErrCode, "errMsg": constant.ErrServer.ErrMsg + err.Error()})
return
}
resp.ErrCode = respPb.ErrCode
resp.ErrMsg = respPb.ErrMsg
resp.Data.ResultKeyValue = respPb.Result
resp.Data.MsgFirstModifyTime = reqPb.MsgFirstModifyTime
resp.Data.IsReact = reqPb.IsReact
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), resp)
c.JSON(http.StatusOK, resp)
}
func GetMessageListReactionExtensions(c *gin.Context) {
var (
req api.GetMessageListReactionExtensionsReq
resp api.GetMessageListReactionExtensionsResp
reqPb rpc.GetMessageListReactionExtensionsReq
)
if err := c.BindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()})
return
}
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req:", req)
if err := utils.CopyStructFields(&reqPb, &req); err != nil {
log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields", err.Error())
}
var ok bool
var errInfo string
ok, reqPb.OpUserID, errInfo = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID)
if !ok {
errMsg := req.OperationID + " " + "GetUserIDFromToken failed " + errInfo + " token:" + c.Request.Header.Get("token")
log.NewError(req.OperationID, errMsg)
c.JSON(http.StatusBadRequest, gin.H{"errCode": 500, "errMsg": errMsg})
return
}
grpcConn := getcdv3.GetDefaultConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImMsgName, req.OperationID)
if grpcConn == nil {
errMsg := req.OperationID + " getcdv3.GetDefaultConn == nil"
log.NewError(req.OperationID, errMsg)
c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg})
return
}
msgClient := rpc.NewMsgClient(grpcConn)
respPb, err := msgClient.GetMessageListReactionExtensions(context.Background(), &reqPb)
if err != nil {
log.NewError(req.OperationID, utils.GetSelfFuncName(), "DelMsgList failed", err.Error(), reqPb)
c.JSON(http.StatusInternalServerError, gin.H{"errCode": constant.ErrServer.ErrCode, "errMsg": constant.ErrServer.ErrMsg + err.Error()})
return
}
resp.ErrCode = respPb.ErrCode
resp.ErrMsg = respPb.ErrMsg
resp.Data = respPb.SingleMessageResult
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), resp)
c.JSON(http.StatusOK, resp)
}
func AddMessageReactionExtensions(c *gin.Context) {
var (
req api.AddMessageReactionExtensionsReq
resp api.AddMessageReactionExtensionsResp
reqPb rpc.ModifyMessageReactionExtensionsReq
)
if err := c.BindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()})
return
}
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req:", req)
if err := utils.CopyStructFields(&reqPb, &req); err != nil {
log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields", err.Error())
}
var ok bool
var errInfo string
ok, reqPb.OpUserID, errInfo = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID)
if !ok {
errMsg := req.OperationID + " " + "GetUserIDFromToken failed " + errInfo + " token:" + c.Request.Header.Get("token")
log.NewError(req.OperationID, errMsg)
c.JSON(http.StatusBadRequest, gin.H{"errCode": 500, "errMsg": errMsg})
return
}
grpcConn := getcdv3.GetDefaultConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImMsgName, req.OperationID)
if grpcConn == nil {
errMsg := req.OperationID + " getcdv3.GetDefaultConn == nil"
log.NewError(req.OperationID, errMsg)
c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg})
return
}
msgClient := rpc.NewMsgClient(grpcConn)
respPb, err := msgClient.AddMessageReactionExtensions(context.Background(), &reqPb)
if err != nil {
log.NewError(req.OperationID, utils.GetSelfFuncName(), "DelMsgList failed", err.Error(), reqPb)
c.JSON(http.StatusInternalServerError, gin.H{"errCode": constant.ErrServer.ErrCode, "errMsg": constant.ErrServer.ErrMsg + err.Error()})
return
}
resp.ErrCode = respPb.ErrCode
resp.ErrMsg = respPb.ErrMsg
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), resp)
c.JSON(http.StatusOK, resp)
}
func DeleteMessageReactionExtensions(c *gin.Context) {
var (
req api.DeleteMessageReactionExtensionsReq
resp api.DeleteMessageReactionExtensionsResp
reqPb rpc.DeleteMessageListReactionExtensionsReq
)
if err := c.BindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()})
return
}
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req:", req)
if err := utils.CopyStructFields(&reqPb, &req); err != nil {
log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "CopyStructFields", err.Error())
}
var ok bool
var errInfo string
ok, reqPb.OpUserID, errInfo = token_verify.GetUserIDFromToken(c.Request.Header.Get("token"), req.OperationID)
if !ok {
errMsg := req.OperationID + " " + "GetUserIDFromToken failed " + errInfo + " token:" + c.Request.Header.Get("token")
log.NewError(req.OperationID, errMsg)
c.JSON(http.StatusBadRequest, gin.H{"errCode": 500, "errMsg": errMsg})
return
}
grpcConn := getcdv3.GetDefaultConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImMsgName, req.OperationID)
if grpcConn == nil {
errMsg := req.OperationID + " getcdv3.GetDefaultConn == nil"
log.NewError(req.OperationID, errMsg)
c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg})
return
}
msgClient := rpc.NewMsgClient(grpcConn)
respPb, err := msgClient.DeleteMessageReactionExtensions(context.Background(), &reqPb)
if err != nil {
log.NewError(req.OperationID, utils.GetSelfFuncName(), "DelMsgList failed", err.Error(), reqPb)
c.JSON(http.StatusInternalServerError, gin.H{"errCode": constant.ErrServer.ErrCode, "errMsg": constant.ErrServer.ErrMsg + err.Error()})
return
}
resp.ErrCode = respPb.ErrCode
resp.ErrMsg = respPb.ErrMsg
resp.Data = respPb.Result
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), resp)
c.JSON(http.StatusOK, resp)
}

View File

@ -58,6 +58,40 @@ func init() {
}
}
func GetUserToken(c *gin.Context) {
var (
req apiStruct.GetUserTokenRequest
resp apiStruct.GetUserTokenResponse
reqPb pbAdmin.GetUserTokenReq
respPb *pbAdmin.GetUserTokenResp
)
if err := c.BindJSON(&req); err != nil {
log.NewError(req.OperationID, utils.GetSelfFuncName(), err.Error())
c.JSON(http.StatusBadRequest, gin.H{"errCode": 400, "errMsg": err.Error()})
return
}
reqPb.OperationID = req.OperationID
reqPb.UserID = req.UserID
reqPb.PlatformID = req.PlatFormID
etcdConn := getcdv3.GetDefaultConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImAdminCMSName, reqPb.OperationID)
if etcdConn == nil {
errMsg := reqPb.OperationID + "getcdv3.GetDefaultConn == nil"
log.NewError(reqPb.OperationID, errMsg)
c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": errMsg})
return
}
client := pbAdmin.NewAdminCMSClient(etcdConn)
respPb, err := client.GetUserToken(context.Background(), &reqPb)
if err != nil {
log.NewError(reqPb.OperationID, utils.GetSelfFuncName(), "rpc failed", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"errCode": 500, "errMsg": err.Error()})
return
}
resp.Token = respPb.Token
resp.ExpTime = respPb.ExpTime
c.JSON(http.StatusOK, gin.H{"errCode": respPb.CommonResp.ErrCode, "errMsg": respPb.CommonResp.ErrMsg, "data": resp})
}
// register
func AdminLogin(c *gin.Context) {
var (

View File

@ -1,6 +1,7 @@
package middleware
import (
"Open_IM/pkg/common/config"
"Open_IM/pkg/common/log"
"Open_IM/pkg/common/token_verify"
"Open_IM/pkg/utils"
@ -20,6 +21,11 @@ func JWTAuth() gin.HandlerFunc {
c.JSON(http.StatusOK, gin.H{"errCode": 400, "errMsg": errInfo})
return
} else {
if !utils.IsContain(userID, config.Config.Manager.AppManagerUid) {
c.Abort()
c.JSON(http.StatusOK, gin.H{"errCode": 400, "errMsg": "user is not admin"})
return
}
log.NewInfo("0", utils.GetSelfFuncName(), "failed: ", errInfo)
}
}

View File

@ -29,6 +29,8 @@ func NewGinRouter() *gin.Engine {
{
adminRouterGroup.POST("/login", admin.AdminLogin)
adminRouterGroup.Use(middleware.JWTAuth())
adminRouterGroup.POST("/get_user_token", admin.GetUserToken)
adminRouterGroup.POST("/add_user_register_add_friend_id", admin.AddUserRegisterAddFriendIDList)
adminRouterGroup.POST("/reduce_user_register_reduce_friend_id", admin.ReduceUserRegisterAddFriendIDList)
adminRouterGroup.POST("/get_user_register_reduce_friend_id_list", admin.GetUserRegisterAddFriendIDList)

View File

@ -7,11 +7,12 @@ import (
"Open_IM/pkg/common/log"
server_api_params "Open_IM/pkg/proto/sdk_ws"
"Open_IM/pkg/utils"
goRedis "github.com/go-redis/redis/v8"
"github.com/golang/protobuf/proto"
"math"
"strconv"
"strings"
goRedis "github.com/go-redis/redis/v8"
"github.com/golang/protobuf/proto"
)
const oldestList = 0
@ -54,7 +55,7 @@ func DeleteMongoMsgAndResetRedisSeq(operationID, userID string) error {
if minSeq == 0 {
return nil
}
log.NewDebug(operationID, utils.GetSelfFuncName(), "delMsgIDMap: ", delStruct, "minSeq", minSeq)
log.NewDebug(operationID, utils.GetSelfFuncName(), "delMsgIDStruct: ", delStruct, "minSeq", minSeq)
err = db.DB.SetUserMinSeq(userID, minSeq)
return utils.Wrap(err, "")
}
@ -82,7 +83,7 @@ func (d *delMsgRecursionStruct) getSetMinSeq() uint32 {
// index 0....19(del) 20...69
// seq 70
// set minSeq 21
// recursion
// recursion 删除list并且返回设置的最小seq
func deleteMongoMsg(operationID string, ID string, index int64, delStruct *delMsgRecursionStruct) (uint32, error) {
// find from oldest list
msgs, err := db.DB.GetUserMsgListByIndex(ID, index)
@ -105,49 +106,52 @@ func deleteMongoMsg(operationID string, ID string, index int64, delStruct *delMs
if len(msgs.Msg) > db.GetSingleGocMsgNum() {
log.NewWarn(operationID, utils.GetSelfFuncName(), "msgs too large", len(msgs.Msg), msgs.UID)
}
for i, msg := range msgs.Msg {
// 找到列表中不需要删除的消息了, 表示为递归到最后一个块
if utils.GetCurrentTimestampByMill() < msg.SendTime+(int64(config.Config.Mongo.DBRetainChatRecords)*24*60*60*1000) {
log.NewDebug(operationID, ID, "find uid", msgs.UID)
// 删除块失败 递归结束 返回0
if err := delMongoMsgsPhysical(delStruct.delUidList); err != nil {
return 0, err
if msgs.Msg[len(msgs.Msg)-1].SendTime+(int64(config.Config.Mongo.DBRetainChatRecords)*24*60*60*1000) < utils.GetCurrentTimestampByMill() && msgListIsFull(msgs) {
delStruct.delUidList = append(delStruct.delUidList, msgs.UID)
lastMsgPb := &server_api_params.MsgData{}
err = proto.Unmarshal(msgs.Msg[len(msgs.Msg)-1].Msg, lastMsgPb)
if err != nil {
log.NewError(operationID, utils.GetSelfFuncName(), err.Error(), len(msgs.Msg)-1, msgs.UID)
return 0, utils.Wrap(err, "proto.Unmarshal failed")
}
delStruct.minSeq = lastMsgPb.Seq + 1
log.NewDebug(operationID, utils.GetSelfFuncName(), msgs.UID, "add to delUidList", "minSeq", lastMsgPb.Seq+1)
} else {
var hasMarkDelFlag bool
for index, msg := range msgs.Msg {
if msg.SendTime == 0 {
continue
}
// unMarshall失败 块删除成功 设置为最小seq
msgPb := &server_api_params.MsgData{}
if err = proto.Unmarshal(msg.Msg, msgPb); err != nil {
return delStruct.getSetMinSeq(), utils.Wrap(err, "")
err = proto.Unmarshal(msg.Msg, msgPb)
if err != nil {
log.NewError(operationID, utils.GetSelfFuncName(), err.Error(), len(msgs.Msg)-1, msgs.UID)
return 0, utils.Wrap(err, "proto.Unmarshal failed")
}
// 如果不是块中第一个,就把前面比他早插入的全部设置空 seq字段除外。
if i > 0 {
err = db.DB.ReplaceMsgToBlankByIndex(msgs.UID, i-1)
if err != nil {
log.NewError(operationID, utils.GetSelfFuncName(), err.Error(), msgs.UID, i)
return delStruct.getSetMinSeq(), utils.Wrap(err, "")
if utils.GetCurrentTimestampByMill() > msg.SendTime+(int64(config.Config.Mongo.DBRetainChatRecords)*24*60*60*1000) {
msgPb.Status = constant.MsgDeleted
bytes, _ := proto.Marshal(msgPb)
msgs.Msg[index].Msg = bytes
msgs.Msg[index].SendTime = 0
hasMarkDelFlag = true
} else {
if err := delMongoMsgsPhysical(delStruct.delUidList); err != nil {
return 0, err
}
if hasMarkDelFlag {
log.NewInfo(operationID, ID, "hasMarkDelFlag", "index:", index, "msgPb:", msgPb, msgs.UID)
if err := db.DB.UpdateOneMsgList(msgs); err != nil {
return delStruct.getSetMinSeq(), utils.Wrap(err, "")
}
}
return msgPb.Seq, nil
}
// 递归结束
return msgPb.Seq, nil
}
}
// 该列表中消息全部为老消息并且列表满了, 加入删除列表继续递归
lastMsgPb := &server_api_params.MsgData{}
err = proto.Unmarshal(msgs.Msg[len(msgs.Msg)-1].Msg, lastMsgPb)
if err != nil {
log.NewError(operationID, utils.GetSelfFuncName(), err.Error(), len(msgs.Msg)-1, msgs.UID)
return 0, utils.Wrap(err, "proto.Unmarshal failed")
}
delStruct.minSeq = lastMsgPb.Seq
if msgListIsFull(msgs) {
delStruct.delUidList = append(delStruct.delUidList, msgs.UID)
}
log.NewDebug(operationID, ID, "continue", delStruct)
log.NewDebug(operationID, ID, "continue to", delStruct)
// 继续递归 index+1
seq, err := deleteMongoMsg(operationID, ID, index+1, delStruct)
if err != nil {
return seq, utils.Wrap(err, "deleteMongoMsg failed")
}
return seq, nil
return seq, utils.Wrap(err, "deleteMongoMsg failed")
}
func msgListIsFull(chat *db.UserChat) bool {
@ -184,17 +188,10 @@ func checkMaxSeqWithMongo(operationID, ID string, diffusionType int) error {
if msg == nil {
return nil
}
var seqMongo uint32
msgPb := &server_api_params.MsgData{}
err = proto.Unmarshal(msg.Msg, msgPb)
if err != nil {
return utils.Wrap(err, "")
}
seqMongo = msgPb.Seq
if math.Abs(float64(seqMongo-uint32(seqRedis))) > 10 {
log.NewWarn(operationID, utils.GetSelfFuncName(), seqMongo, seqRedis, "redis maxSeq is different with msg.Seq > 10", ID, diffusionType)
if math.Abs(float64(msg.Seq-uint32(seqRedis))) > 10 {
log.NewWarn(operationID, utils.GetSelfFuncName(), "seqMongo, seqRedis", msg.Seq, seqRedis, ID, "redis maxSeq is different with msg.Seq > 10", "status: ", msg.Status, msg.SendTime)
} else {
log.NewInfo(operationID, utils.GetSelfFuncName(), diffusionType, ID, "seq and msg OK", seqMongo, seqRedis)
log.NewInfo(operationID, utils.GetSelfFuncName(), "seqMongo, seqRedis", msg.Seq, seqRedis, ID, "seq and msg OK", "status:", msg.Status, msg.SendTime)
}
return nil
}

View File

@ -2,33 +2,225 @@ package cronTask
import (
"Open_IM/pkg/common/constant"
"Open_IM/pkg/common/log"
"Open_IM/pkg/common/db"
server_api_params "Open_IM/pkg/proto/sdk_ws"
"Open_IM/pkg/utils"
"context"
"fmt"
"strconv"
"github.com/go-redis/redis/v8"
"github.com/golang/protobuf/proto"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"gopkg.in/mgo.v2/bson"
"testing"
"time"
)
var (
redisClient *redis.Client
mongoClient *mongo.Collection
)
func GenUserChat(startSeq, stopSeq, delSeq, index uint32, userID string) *db.UserChat {
chat := &db.UserChat{UID: userID + ":" + strconv.Itoa(int(index))}
for i := startSeq; i <= stopSeq; i++ {
msg := server_api_params.MsgData{
SendID: "sendID1",
RecvID: "recvID1",
GroupID: "",
ClientMsgID: "xxx",
ServerMsgID: "xxx",
SenderPlatformID: 1,
SenderNickname: "testNickName",
SenderFaceURL: "testFaceURL",
SessionType: 1,
MsgFrom: 100,
ContentType: 101,
Content: []byte("testFaceURL"),
Seq: uint32(i),
SendTime: time.Now().Unix(),
CreateTime: time.Now().Unix(),
Status: 1,
}
bytes, _ := proto.Marshal(&msg)
var sendTime int64
if i <= delSeq {
sendTime = 10000
} else {
sendTime = utils.GetCurrentTimestampByMill()
}
chat.Msg = append(chat.Msg, db.MsgInfo{SendTime: int64(sendTime), Msg: bytes})
}
return chat
}
func SetUserMaxSeq(userID string, seq int) error {
return redisClient.Set(context.Background(), "REDIS_USER_INCR_SEQ"+userID, seq, 0).Err()
}
func GetUserMinSeq(userID string) (uint64, error) {
key := "REDIS_USER_MIN_SEQ:" + userID
seq, err := redisClient.Get(context.Background(), key).Result()
return uint64(utils.StringToInt(seq)), err
}
func CreateChat(userChat *db.UserChat) error {
_, err := mongoClient.InsertOne(context.Background(), userChat)
return err
}
func DelChat(uid string, index int) error {
_, err := mongoClient.DeleteOne(context.Background(), bson.M{"uid": uid + ":" + strconv.Itoa(index)})
return err
}
func TestDeleteMongoMsgAndResetRedisSeq(t *testing.T) {
operationID := getCronTaskOperationID()
testUserIDList := []string{"test_del_id1", "test_del_id2", "test_del_id3", "test_del_id4", "test_del_id5"}
for _, userID := range testUserIDList {
operationID = userID + "-" + operationID
if err := DeleteMongoMsgAndResetRedisSeq(operationID, userID); err != nil {
t.Error("checkMaxSeqWithMongo failed", userID)
}
if err := checkMaxSeqWithMongo(operationID, userID, constant.WriteDiffusion); err != nil {
t.Error("checkMaxSeqWithMongo failed", userID)
}
redisClient = redis.NewClient(&redis.Options{
Addr: "127.0.0.1:16379",
Password: "openIM123", // no password set
DB: 0, // use default DB
})
mongoUri := fmt.Sprintf("mongodb://%s:%s@%s/%s?maxPoolSize=%d&authSource=admin",
"root", "openIM123", "127.0.0.1:37017",
"openIM", 100)
client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(mongoUri))
mongoClient = client.Database("openIM").Collection("msg")
testUID1 := "test_del_id1"
err = DelChat(testUID1, 0)
err = SetUserMaxSeq(testUID1, 600)
userChat := GenUserChat(1, 600, 200, 0, testUID1)
err = CreateChat(userChat)
if err := DeleteMongoMsgAndResetRedisSeq(operationID, testUID1); err != nil {
t.Error("checkMaxSeqWithMongo failed", testUID1)
}
if err := checkMaxSeqWithMongo(operationID, testUID1, constant.WriteDiffusion); err != nil {
t.Error("checkMaxSeqWithMongo failed", testUID1)
}
minSeq, err := GetUserMinSeq(testUID1)
if err != nil {
t.Error("err is not nil", testUID1, err.Error())
}
if minSeq != 201 {
t.Error("test1 is not the same", "minSeq:", minSeq, "targetSeq", 201)
}
testWorkingGroupIDList := []string{"test_del_id1", "test_del_id2", "test_del_id3", "test_del_id4", "test_del_id5"}
for _, groupID := range testWorkingGroupIDList {
operationID = groupID + "-" + operationID
log.NewDebug(operationID, utils.GetSelfFuncName(), "groupID:", groupID, "userIDList:", testUserIDList)
if err := ResetUserGroupMinSeq(operationID, groupID, testUserIDList); err != nil {
t.Error("checkMaxSeqWithMongo failed", groupID)
}
if err := checkMaxSeqWithMongo(operationID, groupID, constant.ReadDiffusion); err != nil {
t.Error("checkMaxSeqWithMongo failed", groupID)
}
testUID2 := "test_del_id2"
err = DelChat(testUID2, 0)
err = DelChat(testUID2, 1)
err = SetUserMaxSeq(testUID2, 7000)
userChat = GenUserChat(1, 4999, 5000, 0, testUID2)
userChat2 := GenUserChat(5000, 7000, 6000, 1, testUID2)
err = CreateChat(userChat)
err = CreateChat(userChat2)
if err := DeleteMongoMsgAndResetRedisSeq(operationID, testUID2); err != nil {
t.Error("checkMaxSeqWithMongo failed", testUID2)
}
if err := checkMaxSeqWithMongo(operationID, testUID2, constant.WriteDiffusion); err != nil {
t.Error("checkMaxSeqWithMongo failed", testUID2)
}
minSeq, err = GetUserMinSeq(testUID2)
if err != nil {
t.Error("err is not nil", testUID2, err.Error())
}
if minSeq != 6001 {
t.Error("test2 is not the same", "minSeq:", minSeq, "targetSeq", 6001)
}
testUID3 := "test_del_id3"
err = DelChat(testUID3, 0)
err = SetUserMaxSeq(testUID3, 4999)
userChat = GenUserChat(1, 4999, 5000, 0, testUID3)
err = CreateChat(userChat)
if err := DeleteMongoMsgAndResetRedisSeq(operationID, testUID3); err != nil {
t.Error("checkMaxSeqWithMongo failed", testUID3)
}
if err := checkMaxSeqWithMongo(operationID, testUID3, constant.WriteDiffusion); err != nil {
t.Error("checkMaxSeqWithMongo failed", testUID3)
}
minSeq, err = GetUserMinSeq(testUID3)
if err != nil {
t.Error("err is not nil", testUID3, err.Error())
}
if minSeq != 5000 {
t.Error("test3 is not the same", "minSeq:", minSeq, "targetSeq", 5000)
}
testUID4 := "test_del_id4"
err = DelChat(testUID4, 0)
err = DelChat(testUID4, 1)
err = DelChat(testUID4, 2)
err = SetUserMaxSeq(testUID4, 12000)
userChat = GenUserChat(1, 4999, 5000, 0, testUID4)
userChat2 = GenUserChat(5000, 9999, 10000, 1, testUID4)
userChat3 := GenUserChat(10000, 12000, 11000, 2, testUID4)
err = CreateChat(userChat)
err = CreateChat(userChat2)
err = CreateChat(userChat3)
if err := DeleteMongoMsgAndResetRedisSeq(operationID, testUID4); err != nil {
t.Error("checkMaxSeqWithMongo failed", testUID4)
}
if err := checkMaxSeqWithMongo(operationID, testUID4, constant.WriteDiffusion); err != nil {
t.Error("checkMaxSeqWithMongo failed", testUID4)
}
minSeq, err = GetUserMinSeq(testUID4)
if err != nil {
t.Error("err is not nil", testUID4, err.Error())
}
if minSeq != 11001 {
t.Error("test4 is not the same", "minSeq:", minSeq, "targetSeq", 11001)
}
testUID5 := "test_del_id5"
err = DelChat(testUID5, 0)
err = DelChat(testUID5, 1)
err = SetUserMaxSeq(testUID5, 9999)
userChat = GenUserChat(1, 4999, 5000, 0, testUID5)
userChat2 = GenUserChat(5000, 9999, 10000, 1, testUID5)
err = CreateChat(userChat)
err = CreateChat(userChat2)
if err := DeleteMongoMsgAndResetRedisSeq(operationID, testUID5); err != nil {
t.Error("checkMaxSeqWithMongo failed", testUID4)
}
if err := checkMaxSeqWithMongo(operationID, testUID5, constant.WriteDiffusion); err != nil {
t.Error("checkMaxSeqWithMongo failed", testUID5)
}
minSeq, err = GetUserMinSeq(testUID5)
if err != nil {
t.Error("err is not nil", testUID5, err.Error())
}
if minSeq != 10000 {
t.Error("test5 is not the same", "minSeq:", minSeq, "targetSeq", 10000)
}
testUID6 := "test_del_id6"
err = DelChat(testUID5, 0)
err = DelChat(testUID5, 1)
err = DelChat(testUID5, 2)
err = DelChat(testUID5, 3)
userChat = GenUserChat(1, 4999, 5000, 0, testUID6)
userChat2 = GenUserChat(5000, 9999, 10000, 1, testUID6)
userChat3 = GenUserChat(10000, 14999, 13000, 2, testUID6)
userChat4 := GenUserChat(15000, 19999, 0, 3, testUID6)
err = CreateChat(userChat)
err = CreateChat(userChat2)
err = CreateChat(userChat3)
err = CreateChat(userChat4)
if err := DeleteMongoMsgAndResetRedisSeq(operationID, testUID6); err != nil {
t.Error("checkMaxSeqWithMongo failed", testUID6)
}
if err := checkMaxSeqWithMongo(operationID, testUID6, constant.WriteDiffusion); err != nil {
t.Error("checkMaxSeqWithMongo failed", testUID6)
}
minSeq, err = GetUserMinSeq(testUID6)
if err != nil {
t.Error("err is not nil", testUID6, err.Error())
}
if minSeq != 13001 {
t.Error("test3 is not the same", "minSeq:", minSeq, "targetSeq", 13001)
}
}

View File

@ -8,66 +8,35 @@ import (
"Open_IM/pkg/common/log"
"Open_IM/pkg/utils"
"fmt"
"github.com/robfig/cron/v3"
"time"
"github.com/robfig/cron/v3"
)
const cronTaskOperationID = "cronTaskOperationID-"
func StartCronTask() {
func StartCronTask(userID, workingGroupID string) {
log.NewPrivateLog("cron")
log.NewInfo(utils.OperationIDGenerator(), "start cron task", "cron config", config.Config.Mongo.ChatRecordsClearTime)
c := cron.New()
fmt.Println("cron config", config.Config.Mongo.ChatRecordsClearTime)
_, err := c.AddFunc(config.Config.Mongo.ChatRecordsClearTime, func() {
// user msg clear
if userID != "" {
operationID := getCronTaskOperationID()
log.NewInfo(operationID, "====================== start del cron task ======================")
userIDList, err := im_mysql_model.SelectAllUserID()
if err == nil {
log.NewDebug(operationID, utils.GetSelfFuncName(), "userIDList: ", userIDList)
userIDList = []string{"4158779020"}
for _, userID := range userIDList {
if err := DeleteMongoMsgAndResetRedisSeq(operationID, userID); err != nil {
log.NewError(operationID, utils.GetSelfFuncName(), err.Error(), userID)
}
//if err := checkMaxSeqWithMongo(operationID, userID, constant.WriteDiffusion); err != nil {
// log.NewError(operationID, utils.GetSelfFuncName(), userID, err)
//}
}
} else {
log.NewError(operationID, utils.GetSelfFuncName(), err.Error())
}
StartClearMsg(operationID, []string{userID})
}
if workingGroupID != "" {
operationID := getCronTaskOperationID()
StartClearWorkingGroupMsg(operationID, []string{workingGroupID})
}
if userID != "" || workingGroupID != "" {
fmt.Println("clear msg finished")
return
// working group msg clear
workingGroupIDList, err := im_mysql_model.GetGroupIDListByGroupType(constant.WorkingGroup)
if err == nil {
log.NewDebug(operationID, utils.GetSelfFuncName(), "workingGroupIDList: ", workingGroupIDList)
for _, groupID := range workingGroupIDList {
userIDList, err = rocksCache.GetGroupMemberIDListFromCache(groupID)
if err != nil {
log.NewError(operationID, utils.GetSelfFuncName(), err.Error(), groupID)
continue
}
log.NewDebug(operationID, utils.GetSelfFuncName(), "groupID:", groupID, "userIDList:", userIDList)
if err := ResetUserGroupMinSeq(operationID, groupID, userIDList); err != nil {
log.NewError(operationID, utils.GetSelfFuncName(), err.Error(), groupID, userIDList)
}
//if err := checkMaxSeqWithMongo(operationID, groupID, constant.ReadDiffusion); err != nil {
// log.NewError(operationID, utils.GetSelfFuncName(), groupID, err)
//}
}
} else {
log.NewError(operationID, utils.GetSelfFuncName(), err.Error())
}
log.NewInfo(operationID, "====================== start del cron finished ======================")
})
}
c := cron.New()
_, err := c.AddFunc(config.Config.Mongo.ChatRecordsClearTime, ClearAll)
if err != nil {
fmt.Println("start cron failed", err.Error(), config.Config.Mongo.ChatRecordsClearTime)
panic(err)
}
c.Start()
fmt.Println("start cron task success")
for {
@ -78,3 +47,55 @@ func StartCronTask() {
func getCronTaskOperationID() string {
return cronTaskOperationID + utils.OperationIDGenerator()
}
func ClearAll() {
operationID := getCronTaskOperationID()
log.NewInfo(operationID, "====================== start del cron task ======================")
var err error
userIDList, err := im_mysql_model.SelectAllUserID()
if err == nil {
StartClearMsg(operationID, userIDList)
} else {
log.NewError(operationID, utils.GetSelfFuncName(), err.Error())
}
// working group msg clear
workingGroupIDList, err := im_mysql_model.GetGroupIDListByGroupType(constant.WorkingGroup)
if err == nil {
StartClearWorkingGroupMsg(operationID, workingGroupIDList)
} else {
log.NewError(operationID, utils.GetSelfFuncName(), err.Error())
}
log.NewInfo(operationID, "====================== start del cron finished ======================")
}
func StartClearMsg(operationID string, userIDList []string) {
log.NewDebug(operationID, utils.GetSelfFuncName(), "userIDList: ", userIDList)
for _, userID := range userIDList {
if err := DeleteMongoMsgAndResetRedisSeq(operationID, userID); err != nil {
log.NewError(operationID, utils.GetSelfFuncName(), err.Error(), userID)
}
if err := checkMaxSeqWithMongo(operationID, userID, constant.WriteDiffusion); err != nil {
log.NewError(operationID, utils.GetSelfFuncName(), userID, err)
}
}
}
func StartClearWorkingGroupMsg(operationID string, workingGroupIDList []string) {
log.NewDebug(operationID, utils.GetSelfFuncName(), "workingGroupIDList: ", workingGroupIDList)
for _, groupID := range workingGroupIDList {
userIDList, err := rocksCache.GetGroupMemberIDListFromCache(groupID)
if err != nil {
log.NewError(operationID, utils.GetSelfFuncName(), err.Error(), groupID)
continue
}
log.NewDebug(operationID, utils.GetSelfFuncName(), "groupID:", groupID, "workingGroupIDList:", userIDList)
if err := ResetUserGroupMinSeq(operationID, groupID, userIDList); err != nil {
log.NewError(operationID, utils.GetSelfFuncName(), err.Error(), groupID, userIDList)
}
if err := checkMaxSeqWithMongo(operationID, groupID, constant.ReadDiffusion); err != nil {
log.NewError(operationID, utils.GetSelfFuncName(), groupID, err)
}
}
}

View File

@ -1,6 +0,0 @@
package main
//
//func main() {
// db.DB.BatchInsertChat()
//}

View File

@ -10,7 +10,6 @@ import (
"github.com/gin-gonic/gin"
//"github.com/jinzhu/gorm"
"net/http"
"time"
)

View File

@ -9,7 +9,7 @@ import (
"time"
)
func callbackUserOnline(operationID, userID string, platformID int, token string) cbApi.CommonCallbackResp {
func callbackUserOnline(operationID, userID string, platformID int, token string, isAppBackground bool, connID string) cbApi.CommonCallbackResp {
callbackResp := cbApi.CommonCallbackResp{OperationID: operationID}
if !config.Config.Callback.CallbackUserOnline.Enable {
return callbackResp
@ -25,7 +25,9 @@ func callbackUserOnline(operationID, userID string, platformID int, token string
},
UserID: userID,
},
Seq: int(time.Now().UnixNano() / 1e6),
Seq: int(time.Now().UnixNano() / 1e6),
IsAppBackground: isAppBackground,
ConnID: connID,
}
callbackUserOnlineResp := &cbApi.CallbackUserOnlineResp{CommonCallbackResp: &callbackResp}
if err := http.CallBackPostReturn(config.Config.Callback.CallbackUrl, constant.CallbackUserOnlineCommand, callbackUserOnlineReq, callbackUserOnlineResp, config.Config.Callback.CallbackUserOnline.CallbackTimeOut); err != nil {
@ -35,7 +37,7 @@ func callbackUserOnline(operationID, userID string, platformID int, token string
return callbackResp
}
func callbackUserOffline(operationID, userID string, platformID int) cbApi.CommonCallbackResp {
func callbackUserOffline(operationID, userID string, platformID int, connID string) cbApi.CommonCallbackResp {
callbackResp := cbApi.CommonCallbackResp{OperationID: operationID}
if !config.Config.Callback.CallbackUserOffline.Enable {
return callbackResp
@ -50,7 +52,8 @@ func callbackUserOffline(operationID, userID string, platformID int) cbApi.Commo
},
UserID: userID,
},
Seq: int(time.Now().UnixNano() / 1e6),
Seq: int(time.Now().UnixNano() / 1e6),
ConnID: connID,
}
callbackUserOfflineResp := &cbApi.CallbackUserOfflineResp{CommonCallbackResp: &callbackResp}
if err := http.CallBackPostReturn(config.Config.Callback.CallbackUrl, constant.CallbackUserOfflineCommand, callbackOfflineReq, callbackUserOfflineResp, config.Config.Callback.CallbackUserOffline.CallbackTimeOut); err != nil {

View File

@ -15,10 +15,12 @@ import (
"bytes"
"context"
"encoding/gob"
"github.com/golang/protobuf/proto"
"github.com/gorilla/websocket"
"runtime"
"strings"
"github.com/golang/protobuf/proto"
"github.com/gorilla/websocket"
"google.golang.org/grpc"
)
func (ws *WServer) msgParse(conn *UserConn, binaryMsg []byte) {
@ -65,6 +67,9 @@ func (ws *WServer) msgParse(conn *UserConn, binaryMsg []byte) {
case constant.WsLogoutMsg:
log.NewInfo(m.OperationID, "conn.Close()", m.SendID, m.MsgIncr, m.ReqIdentifier)
ws.userLogoutReq(conn, &m)
case constant.WsSetBackgroundStatus:
log.NewInfo(m.OperationID, "WsSetBackgroundStatus", m.SendID, m.MsgIncr, m.ReqIdentifier)
ws.setUserDeviceBackground(conn, &m)
default:
log.Error(m.OperationID, "ReqIdentifier failed ", m.SendID, m.MsgIncr, m.ReqIdentifier)
}
@ -147,7 +152,8 @@ func (ws *WServer) pullMsgBySeqListReq(conn *UserConn, m *Req) {
return
}
msgClient := pbChat.NewMsgClient(grpcConn)
reply, err := msgClient.PullMessageBySeqList(context.Background(), &rpcReq)
maxSizeOption := grpc.MaxCallRecvMsgSize(1024 * 1024 * 20)
reply, err := msgClient.PullMessageBySeqList(context.Background(), &rpcReq, maxSizeOption)
if err != nil {
log.NewError(rpcReq.OperationID, "pullMsgBySeqListReq err", err.Error())
nReply.ErrCode = 200
@ -180,8 +186,10 @@ func (ws *WServer) pullMsgBySeqListResp(conn *UserConn, m *Req, pb *sdk_ws.PullM
}
func (ws *WServer) userLogoutReq(conn *UserConn, m *Req) {
log.NewInfo(m.OperationID, "Ws call success to userLogoutReq start", m.SendID, m.ReqIdentifier, m.MsgIncr, string(m.Data))
rpcReq := push.DelUserPushTokenReq{}
rpcReq.UserID = m.SendID
rpcReq.PlatformID = conn.PlatformID
rpcReq.OperationID = m.OperationID
grpcConn := getcdv3.GetDefaultConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImPushName, m.OperationID)
if grpcConn == nil {
@ -394,3 +402,28 @@ func SetTokenKicked(userID string, platformID int, operationID string) {
return
}
}
func (ws *WServer) setUserDeviceBackground(conn *UserConn, m *Req) {
isPass, errCode, errMsg, pData := ws.argsValidate(m, constant.WsSetBackgroundStatus, m.OperationID)
if isPass {
req := pData.(*sdk_ws.SetAppBackgroundStatusReq)
conn.IsBackground = req.IsBackground
callbackResp := callbackUserOnline(m.OperationID, conn.userID, int(conn.PlatformID), conn.token, conn.IsBackground, conn.connID)
if callbackResp.ErrCode != 0 {
log.NewError(m.OperationID, utils.GetSelfFuncName(), "callbackUserOffline failed", callbackResp)
}
log.NewInfo(m.OperationID, "SetUserDeviceBackground", "success", *conn, req.IsBackground)
}
ws.setUserDeviceBackgroundResp(conn, m, errCode, errMsg)
}
func (ws *WServer) setUserDeviceBackgroundResp(conn *UserConn, m *Req, errCode int32, errMsg string) {
mReply := Resp{
ReqIdentifier: m.ReqIdentifier,
MsgIncr: m.MsgIncr,
OperationID: m.OperationID,
ErrCode: errCode,
ErrMsg: errMsg,
}
ws.sendMsg(conn, mReply)
}

View File

@ -159,6 +159,8 @@ func (r *RPCServer) GetUsersOnlineStatus(_ context.Context, req *pbRelay.GetUser
ps := new(pbRelay.GetUsersOnlineStatusResp_SuccessDetail)
ps.Platform = constant.PlatformIDToName(platform)
ps.Status = constant.OnlineStatus
ps.ConnID = userConn.connID
ps.IsBackground = userConn.IsBackground
temp.Status = constant.OnlineStatus
temp.DetailPlatformStatus = append(temp.DetailPlatformStatus, ps)
}
@ -196,24 +198,75 @@ func (r *RPCServer) SuperGroupOnlineBatchPushOneMsg(_ context.Context, req *pbRe
userConnMap := ws.getUserAllCons(v)
for platform, userConn := range userConnMap {
if userConn != nil {
resultCode := sendMsgBatchToUser(userConn, replyBytes.Bytes(), req, platform, v)
if resultCode == 0 && utils.IsContainInt(platform, r.pushTerminal) {
tempT.OnlinePush = true
promePkg.PromeInc(promePkg.MsgOnlinePushSuccessCounter)
log.Info(req.OperationID, "PushSuperMsgToUser is success By Ws", "args", req.String(), "recvPlatForm", constant.PlatformIDToName(platform), "recvID", v)
temp := &pbRelay.SingleMsgToUserPlatform{
ResultCode: resultCode,
RecvID: v,
RecvPlatFormID: int32(platform),
temp := &pbRelay.SingleMsgToUserPlatform{
RecvID: v,
RecvPlatFormID: int32(platform),
}
if !userConn.IsBackground {
resultCode := sendMsgBatchToUser(userConn, replyBytes.Bytes(), req, platform, v)
if resultCode == 0 && utils.IsContainInt(platform, r.pushTerminal) {
tempT.OnlinePush = true
promePkg.PromeInc(promePkg.MsgOnlinePushSuccessCounter)
log.Info(req.OperationID, "PushSuperMsgToUser is success By Ws", "args", req.String(), "recvPlatForm", constant.PlatformIDToName(platform), "recvID", v)
temp.ResultCode = resultCode
resp = append(resp, temp)
}
} else {
temp.ResultCode = -2
resp = append(resp, temp)
}
}
}
tempT.Resp = resp
singleUserResult = append(singleUserResult, tempT)
}
return &pbRelay.OnlineBatchPushOneMsgResp{
SinglePushResult: singleUserResult,
}, nil
}
func (r *RPCServer) SuperGroupBackgroundOnlinePush(_ context.Context, req *pbRelay.OnlineBatchPushOneMsgReq) (*pbRelay.OnlineBatchPushOneMsgResp, error) {
log.NewInfo(req.OperationID, "BatchPushMsgToUser is arriving", req.String())
var singleUserResult []*pbRelay.SingelMsgToUserResultList
//r.GetBatchMsgForPush(req.OperationID,req.MsgData,req.PushToUserIDList,)
msgBytes, _ := proto.Marshal(req.MsgData)
mReply := Resp{
ReqIdentifier: constant.WSPushMsg,
OperationID: req.OperationID,
Data: msgBytes,
}
var replyBytes bytes.Buffer
enc := gob.NewEncoder(&replyBytes)
err := enc.Encode(mReply)
if err != nil {
log.NewError(req.OperationID, "data encode err", err.Error())
}
for _, v := range req.PushToUserIDList {
var resp []*pbRelay.SingleMsgToUserPlatform
tempT := &pbRelay.SingelMsgToUserResultList{
UserID: v,
}
userConnMap := ws.getUserAllCons(v)
for platform, userConn := range userConnMap {
if userConn != nil && userConn.IsBackground {
temp := &pbRelay.SingleMsgToUserPlatform{
RecvID: v,
RecvPlatFormID: int32(platform),
}
if constant.PlatformIDToClass(int(userConn.PlatformID)) == constant.TerminalPC || userConn.PlatformID == constant.WebPlatformID {
resultCode := sendMsgBatchToUser(userConn, replyBytes.Bytes(), req, platform, v)
if resultCode == 0 && utils.IsContainInt(platform, r.pushTerminal) {
tempT.OnlinePush = true
promePkg.PromeInc(promePkg.MsgOnlinePushSuccessCounter)
log.Info(req.OperationID, "PushSuperMsgToUser is success By Ws", "args", req.String(), "recvPlatForm", constant.PlatformIDToName(platform), "recvID", v)
temp.ResultCode = resultCode
resp = append(resp, temp)
}
}
}
}
tempT.Resp = resp
singleUserResult = append(singleUserResult, tempT)
}
return &pbRelay.OnlineBatchPushOneMsgResp{

View File

@ -107,6 +107,18 @@ func (ws *WServer) argsValidate(m *Req, r int32, operationID string) (isPass boo
}
return true, 0, "", data
case constant.WsSetBackgroundStatus:
data := open_im_sdk.SetAppBackgroundStatusReq{}
if err := proto.Unmarshal(m.Data, &data); err != nil {
log.Error(operationID, "Decode Data struct err", err.Error(), r)
return false, 203, err.Error(), nil
}
if err := validate.Struct(data); err != nil {
log.Error(operationID, "data args validate err", err.Error(), r)
return false, 204, err.Error(), nil
}
return true, 0, "", &data
default:
}
return false, 204, "args err", nil

View File

@ -15,6 +15,7 @@ import (
"context"
"encoding/gob"
"io/ioutil"
"strconv"
"strings"
go_redis "github.com/go-redis/redis/v8"
@ -31,11 +32,15 @@ import (
type UserConn struct {
*websocket.Conn
w *sync.Mutex
platformID int32
PlatformID int32
PushedMaxSeq uint32
IsCompress bool
userID string
IsBackground bool
token string
connID string
}
type WServer struct {
wsAddr string
wsMaxConnNum int
@ -73,20 +78,15 @@ func (ws *WServer) wsHandler(w http.ResponseWriter, r *http.Request) {
operationID = utils.OperationIDGenerator()
}
log.Debug(operationID, utils.GetSelfFuncName(), " args: ", query)
if ws.headerCheck(w, r, operationID) {
if isPass, compression := ws.headerCheck(w, r, operationID); isPass {
conn, err := ws.wsUpGrader.Upgrade(w, r, nil) //Conn is obtained through the upgraded escalator
if err != nil {
log.Error(operationID, "upgrade http conn err", err.Error(), query)
return
} else {
var isCompress = false
if r.Header.Get("compression") == "gzip" {
log.NewDebug(operationID, query["sendID"][0], "enable compression")
isCompress = true
}
newConn := &UserConn{conn, new(sync.Mutex), utils.StringToInt32(query["platformID"][0]), 0, isCompress, query["sendID"][0]}
newConn := &UserConn{conn, new(sync.Mutex), utils.StringToInt32(query["platformID"][0]), 0, compression, query["sendID"][0], false, query["token"][0], conn.RemoteAddr().String() + "_" + strconv.Itoa(int(utils.GetCurrentTimestampByMill()))}
userCount++
ws.addUserConn(query["sendID"][0], utils.StringToInt(query["platformID"][0]), newConn, query["token"][0], operationID)
ws.addUserConn(query["sendID"][0], utils.StringToInt(query["platformID"][0]), newConn, query["token"][0], newConn.connID, operationID)
go ws.readMsg(newConn)
}
} else {
@ -221,7 +221,7 @@ func (ws *WServer) MultiTerminalLoginCheckerWithLock(uid string, platformID int,
return
}
err = oldConn.Close()
delete(oldConnMap, platformID)
//delete(oldConnMap, platformID)
ws.wsUserToConn[uid] = oldConnMap
if len(oldConnMap) == 0 {
delete(ws.wsUserToConn, uid)
@ -321,11 +321,11 @@ func (ws *WServer) sendKickMsg(oldConn *UserConn) {
}
}
func (ws *WServer) addUserConn(uid string, platformID int, conn *UserConn, token string, operationID string) {
func (ws *WServer) addUserConn(uid string, platformID int, conn *UserConn, token string, connID, operationID string) {
rwLock.Lock()
defer rwLock.Unlock()
log.Info(operationID, utils.GetSelfFuncName(), " args: ", uid, platformID, conn, token, "ip: ", conn.RemoteAddr().String())
callbackResp := callbackUserOnline(operationID, uid, platformID, token)
callbackResp := callbackUserOnline(operationID, uid, platformID, token, false, connID)
if callbackResp.ErrCode != 0 {
log.NewError(operationID, utils.GetSelfFuncName(), "callbackUserOnline resp:", callbackResp)
}
@ -363,7 +363,7 @@ func (ws *WServer) delUserConn(conn *UserConn) {
operationID := utils.OperationIDGenerator()
var uid string
var platform int
if oldStringMap, ok := ws.wsConnToUser[conn]; ok {
if oldStringMap, okg := ws.wsConnToUser[conn]; okg {
for k, v := range oldStringMap {
platform = k
uid = v
@ -383,17 +383,20 @@ func (ws *WServer) delUserConn(conn *UserConn) {
log.Debug(operationID, "WS delete operation", "", "wsUser deleted", ws.wsUserToConn, "disconnection_uid", uid, "disconnection_platform", platform, "online_user_num", len(ws.wsUserToConn))
}
delete(ws.wsConnToUser, conn)
}
err := conn.Close()
if err != nil {
log.Error(operationID, " close err", "", "uid", uid, "platform", platform)
}
callbackResp := callbackUserOffline(operationID, uid, platform)
if conn.PlatformID == 0 || conn.connID == "" {
log.NewWarn(operationID, utils.GetSelfFuncName(), "PlatformID or connID is null", conn.PlatformID, conn.connID)
}
callbackResp := callbackUserOffline(operationID, conn.userID, int(conn.PlatformID), conn.connID)
if callbackResp.ErrCode != 0 {
log.NewError(operationID, utils.GetSelfFuncName(), "callbackUserOffline failed", callbackResp)
}
promePkg.PromeGaugeDec(promePkg.OnlineUserGauge)
}
func (ws *WServer) getUserConn(uid string, platform int) *UserConn {
@ -432,7 +435,7 @@ func (ws *WServer) getUserAllCons(uid string) map[int]*UserConn {
// }
// return "", 0
//}
func (ws *WServer) headerCheck(w http.ResponseWriter, r *http.Request, operationID string) bool {
func (ws *WServer) headerCheck(w http.ResponseWriter, r *http.Request, operationID string) (isPass, compression bool) {
status := http.StatusUnauthorized
query := r.URL.Query()
if len(query["token"]) != 0 && len(query["sendID"]) != 0 && len(query["platformID"]) != 0 {
@ -484,10 +487,16 @@ func (ws *WServer) headerCheck(w http.ResponseWriter, r *http.Request, operation
w.Header().Set("Sec-Websocket-Version", "13")
w.Header().Set("ws_err_msg", err.Error())
http.Error(w, err.Error(), status)
return false
return false, false
} else {
log.Info(operationID, "Connection Authentication Success", "", "token ", query["token"][0], "userID ", query["sendID"][0], "platformID ", query["platformID"][0])
return true
if r.Header.Get("compression") == "gzip" {
compression = true
}
if len(query["compression"]) != 0 && query["compression"][0] == "gzip" {
compression = true
}
log.Info(operationID, "Connection Authentication Success", "", "token ", query["token"][0], "userID ", query["sendID"][0], "platformID ", query["platformID"][0], "compression", compression)
return true, compression
}
} else {
status = int(constant.ErrArgs.ErrCode)
@ -496,6 +505,6 @@ func (ws *WServer) headerCheck(w http.ResponseWriter, r *http.Request, operation
errMsg := "args err, need token, sendID, platformID"
w.Header().Set("ws_err_msg", errMsg)
http.Error(w, errMsg, status)
return false
return false, false
}
}

View File

@ -22,7 +22,9 @@ var (
persistentCH PersistentConsumerHandler
historyCH OnlineHistoryRedisConsumerHandler
historyMongoCH OnlineHistoryMongoConsumerHandler
modifyCH ModifyMsgConsumerHandler
producer *kafka.Producer
producerToModify *kafka.Producer
producerToMongo *kafka.Producer
cmdCh chan Cmd2Value
onlineTopicStatus int
@ -43,11 +45,13 @@ func Init() {
persistentCH.Init() // ws2mschat save mysql
historyCH.Init(cmdCh) //
historyMongoCH.Init()
modifyCH.Init()
onlineTopicStatus = OnlineTopicVacancy
//offlineHistoryCH.Init(cmdCh)
statistics.NewStatistics(&singleMsgSuccessCount, config.Config.ModuleName.MsgTransferName, fmt.Sprintf("%d second singleMsgCount insert to mongo", constant.StatisticsTimeInterval), constant.StatisticsTimeInterval)
statistics.NewStatistics(&groupMsgCount, config.Config.ModuleName.MsgTransferName, fmt.Sprintf("%d second groupMsgCount insert to mongo", constant.StatisticsTimeInterval), constant.StatisticsTimeInterval)
producer = kafka.NewKafkaProducer(config.Config.Kafka.Ms2pschat.Addr, config.Config.Kafka.Ms2pschat.Topic)
producerToModify = kafka.NewKafkaProducer(config.Config.Kafka.MsgToModify.Addr, config.Config.Kafka.MsgToModify.Topic)
producerToMongo = kafka.NewKafkaProducer(config.Config.Kafka.MsgToMongo.Addr, config.Config.Kafka.MsgToMongo.Topic)
}
func Run(promethuesPort int) {
@ -59,6 +63,7 @@ func Run(promethuesPort int) {
}
go historyCH.historyConsumerGroup.RegisterHandleAndConsumer(&historyCH)
go historyMongoCH.historyConsumerGroup.RegisterHandleAndConsumer(&historyMongoCH)
go modifyCH.modifyMsgConsumerGroup.RegisterHandleAndConsumer(&modifyCH)
//go offlineHistoryCH.historyConsumerGroup.RegisterHandleAndConsumer(&offlineHistoryCH)
go func() {
err := promePkg.StartPromeSrv(promethuesPort)

View File

@ -0,0 +1,121 @@
package logic
import (
"Open_IM/pkg/base_info"
"Open_IM/pkg/common/config"
"Open_IM/pkg/common/constant"
"Open_IM/pkg/common/db"
kfk "Open_IM/pkg/common/kafka"
"Open_IM/pkg/common/log"
pbMsg "Open_IM/pkg/proto/msg"
server_api_params "Open_IM/pkg/proto/sdk_ws"
"Open_IM/pkg/utils"
"encoding/json"
"github.com/Shopify/sarama"
"github.com/golang/protobuf/proto"
)
type ModifyMsgConsumerHandler struct {
msgHandle map[string]fcb
modifyMsgConsumerGroup *kfk.MConsumerGroup
}
func (mmc *ModifyMsgConsumerHandler) Init() {
mmc.msgHandle = make(map[string]fcb)
mmc.msgHandle[config.Config.Kafka.MsgToModify.Topic] = mmc.ModifyMsg
mmc.modifyMsgConsumerGroup = kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{KafkaVersion: sarama.V2_0_0_0,
OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false}, []string{config.Config.Kafka.MsgToModify.Topic},
config.Config.Kafka.MsgToModify.Addr, config.Config.Kafka.ConsumerGroupID.MsgToModify)
}
func (ModifyMsgConsumerHandler) Setup(_ sarama.ConsumerGroupSession) error { return nil }
func (ModifyMsgConsumerHandler) Cleanup(_ sarama.ConsumerGroupSession) error { return nil }
func (mmc *ModifyMsgConsumerHandler) ConsumeClaim(sess sarama.ConsumerGroupSession,
claim sarama.ConsumerGroupClaim) error {
for msg := range claim.Messages() {
log.NewDebug("", "kafka get info to mysql", "ModifyMsgConsumerHandler", msg.Topic, "msgPartition", msg.Partition, "msg", string(msg.Value), "key", string(msg.Key))
if len(msg.Value) != 0 {
mmc.msgHandle[msg.Topic](msg, string(msg.Key), sess)
} else {
log.Error("", "msg get from kafka but is nil", msg.Key)
}
sess.MarkMessage(msg, "")
}
return nil
}
func (mmc *ModifyMsgConsumerHandler) ModifyMsg(cMsg *sarama.ConsumerMessage, msgKey string, _ sarama.ConsumerGroupSession) {
log.NewInfo("msg come here ModifyMsg!!!", "", "msg", string(cMsg.Value), msgKey)
msgFromMQ := pbMsg.MsgDataToModifyByMQ{}
err := proto.Unmarshal(cMsg.Value, &msgFromMQ)
if err != nil {
log.NewError(msgFromMQ.TriggerID, "msg_transfer Unmarshal msg err", "msg", string(cMsg.Value), "err", err.Error())
return
}
log.Debug(msgFromMQ.TriggerID, "proto.Unmarshal MsgDataToMQ", msgFromMQ.String())
for _, msgDataToMQ := range msgFromMQ.MessageList {
isReactionFromCache := utils.GetSwitchFromOptions(msgDataToMQ.MsgData.Options, constant.IsReactionFromCache)
if !isReactionFromCache {
continue
}
if msgDataToMQ.MsgData.ContentType == constant.ReactionMessageModifier {
notification := &base_info.ReactionMessageModifierNotification{}
if err := json.Unmarshal(msgDataToMQ.MsgData.Content, notification); err != nil {
continue
}
if notification.IsExternalExtensions {
log.NewInfo(msgDataToMQ.OperationID, "msg:", notification, "this is external extensions")
continue
}
if !notification.IsReact {
// first time to modify
var reactionExtensionList = make(map[string]db.KeyValue)
extendMsg := db.ExtendMsg{
ReactionExtensionList: reactionExtensionList,
ClientMsgID: notification.ClientMsgID,
MsgFirstModifyTime: notification.MsgFirstModifyTime,
}
for _, v := range notification.SuccessReactionExtensionList {
reactionExtensionList[v.TypeKey] = db.KeyValue{
TypeKey: v.TypeKey,
Value: v.Value,
LatestUpdateTime: v.LatestUpdateTime,
}
}
if err := db.DB.InsertExtendMsg(notification.SourceID, notification.SessionType, &extendMsg); err != nil {
log.NewError(msgDataToMQ.OperationID, "MsgFirstModify InsertExtendMsg failed", notification.SourceID, notification.SessionType, extendMsg, err.Error())
continue
}
} else {
var reactionExtensionList = make(map[string]*server_api_params.KeyValue)
for _, v := range notification.SuccessReactionExtensionList {
reactionExtensionList[v.TypeKey] = &server_api_params.KeyValue{
TypeKey: v.TypeKey,
Value: v.Value,
LatestUpdateTime: v.LatestUpdateTime,
}
}
// is already modify
if err := db.DB.InsertOrUpdateReactionExtendMsgSet(notification.SourceID, notification.SessionType, notification.ClientMsgID, notification.MsgFirstModifyTime, reactionExtensionList); err != nil {
log.NewError(msgDataToMQ.OperationID, "InsertOrUpdateReactionExtendMsgSet failed")
}
}
} else if msgDataToMQ.MsgData.ContentType == constant.ReactionMessageDeleter {
notification := &base_info.ReactionMessageDeleteNotification{}
if err := json.Unmarshal(msgDataToMQ.MsgData.Content, notification); err != nil {
continue
}
if err := db.DB.DeleteReactionExtendMsgSet(notification.SourceID, notification.SessionType, notification.ClientMsgID, notification.MsgFirstModifyTime, notification.SuccessReactionExtensionList); err != nil {
log.NewError(msgDataToMQ.OperationID, "InsertOrUpdateReactionExtendMsgSet failed")
}
}
}
}
func UnMarshallSetReactionMsgContent(content []byte) (notification *base_info.ReactionMessageModifierNotification, err error) {
return notification, nil
}

View File

@ -72,6 +72,7 @@ func (och *OnlineHistoryRedisConsumerHandler) Run(channelID int) {
storageMsgList := make([]*pbMsg.MsgDataToMQ, 0, 80)
notStoragePushMsgList := make([]*pbMsg.MsgDataToMQ, 0, 80)
log.Debug(triggerID, "msg arrived channel", "channel id", channelID, msgList, msgChannelValue.aggregationID, len(msgList))
var modifyMsgList []*pbMsg.MsgDataToMQ
for _, v := range msgList {
log.Debug(triggerID, "msg come to storage center", v.String())
isHistory := utils.GetSwitchFromOptions(v.MsgData.Options, constant.IsHistory)
@ -83,11 +84,15 @@ func (och *OnlineHistoryRedisConsumerHandler) Run(channelID int) {
if !(!isSenderSync && msgChannelValue.aggregationID == v.MsgData.SendID) {
notStoragePushMsgList = append(notStoragePushMsgList, v)
}
}
if v.MsgData.ContentType == constant.ReactionMessageModifier || v.MsgData.ContentType == constant.ReactionMessageDeleter {
modifyMsgList = append(modifyMsgList, v)
}
}
if len(modifyMsgList) > 0 {
sendMessageToModifyMQ(msgChannelValue.aggregationID, triggerID, modifyMsgList)
}
//switch msgChannelValue.msg.MsgData.SessionType {
//case constant.SingleChatType:
//case constant.GroupChatType:
@ -107,6 +112,7 @@ func (och *OnlineHistoryRedisConsumerHandler) Run(channelID int) {
singleMsgSuccessCount += uint64(len(storageMsgList))
singleMsgSuccessCountMutex.Unlock()
och.SendMessageToMongoCH(msgChannelValue.aggregationID, triggerID, storageMsgList, lastSeq)
for _, v := range storageMsgList {
sendMessageToPushMQ(v, msgChannelValue.aggregationID)
}
@ -552,6 +558,17 @@ func sendMessageToPushMQ(message *pbMsg.MsgDataToMQ, pushToUserID string) {
return
}
func sendMessageToModifyMQ(aggregationID string, triggerID string, messages []*pbMsg.MsgDataToMQ) {
if len(messages) > 0 {
pid, offset, err := producerToModify.SendMessage(&pbMsg.MsgDataToModifyByMQ{AggregationID: aggregationID, MessageList: messages, TriggerID: triggerID}, aggregationID, triggerID)
if err != nil {
log.Error(triggerID, "kafka send failed", "send data", len(messages), "pid", pid, "offset", offset, "err", err.Error(), "key", aggregationID)
} else {
// log.NewWarn(m.OperationID, "sendMsgToKafka client msgID ", m.MsgData.ClientMsgID)
}
}
}
// String hashes a string to a unique hashcode.
//
// crc32 returns a uint32, but for our use we need

View File

@ -61,7 +61,6 @@ func (mc *OnlineHistoryMongoConsumerHandler) handleChatWs2Mongo(cMsg *sarama.Con
if unexistSeqList, err := db.DB.DelMsgBySeqList(DeleteMessageTips.UserID, DeleteMessageTips.SeqList, v.OperationID); err != nil {
log.NewError(v.OperationID, utils.GetSelfFuncName(), "DelMsgBySeqList args: ", DeleteMessageTips.UserID, DeleteMessageTips.SeqList, v.OperationID, err.Error(), unexistSeqList)
}
}
}
}

View File

@ -26,8 +26,10 @@ var (
)
const (
PushURL = "/push/single/alias"
AuthURL = "/auth"
PushURL = "/push/single/alias"
AuthURL = "/auth"
TaskURL = "/push/list/message"
BatchPushURL = "/push/list/alias"
)
func init() {
@ -53,23 +55,42 @@ type AuthResp struct {
Token string `json:"token"`
}
type TaskResp struct {
TaskID string `json:"taskID"`
}
type Settings struct {
TTL *int64 `json:"ttl"`
}
type Audience struct {
Alias []string `json:"alias"`
}
type PushMessage struct {
Notification *Notification `json:"notification,omitempty"`
Transmission *string `json:"transmission,omitempty"`
}
type PushChannel struct {
Ios *Ios `json:"ios"`
Android *Android `json:"android"`
}
type PushReq struct {
RequestID string `json:"request_id"`
Audience struct {
Alias []string `json:"alias"`
} `json:"audience"`
PushMessage struct {
Notification Notification `json:"notification,omitempty"`
Transmission string `json:"transmission,omitempty"`
} `json:"push_message"`
PushChannel struct {
Ios Ios `json:"ios"`
Android Android `json:"android"`
} `json:"push_channel"`
RequestID *string `json:"request_id"`
Settings *Settings `json:"settings"`
Audience *Audience `json:"audience"`
PushMessage *PushMessage `json:"push_message"`
PushChannel *PushChannel `json:"push_channel"`
IsAsync *bool `json:"is_async"`
Taskid *string `json:"taskid"`
}
type Ios struct {
Aps struct {
NotiType *string `json:"type"`
AutoBadge *string `json:"auto_badge"`
Aps struct {
Sound string `json:"sound"`
Alert Alert `json:"alert"`
} `json:"aps"`
@ -119,9 +140,9 @@ func newGetuiClient() *Getui {
func (g *Getui) Push(userIDList []string, title, detailContent, operationID string, opts push.PushOpts) (resp string, err error) {
token, err := db.DB.GetGetuiToken()
log.NewDebug(operationID, utils.GetSelfFuncName(), "token", token)
log.NewDebug(operationID, utils.GetSelfFuncName(), "token", token, userIDList)
if err != nil {
log.NewError(operationID, utils.OperationIDGenerator(), "GetGetuiToken failed", err.Error())
log.NewError(operationID, utils.GetSelfFuncName(), "GetGetuiToken failed", err.Error())
}
if token == "" || err != nil {
token, err = g.getTokenAndSave2Redis(operationID)
@ -130,47 +151,32 @@ func (g *Getui) Push(userIDList []string, title, detailContent, operationID stri
return "", utils.Wrap(err, "")
}
}
pushReq := PushReq{
RequestID: utils.OperationIDGenerator(),
Audience: struct {
Alias []string `json:"alias"`
}{Alias: []string{userIDList[0]}},
}
pushReq.PushMessage.Notification = Notification{
pushReq := PushReq{PushMessage: &PushMessage{Notification: &Notification{
Title: title,
Body: detailContent,
ClickType: "startapp",
ChannelID: config.Config.Push.Getui.ChannelID,
ChannelName: config.Config.Push.Getui.ChannelName,
}
pushReq.PushChannel.Ios.Aps.Sound = "default"
pushReq.PushChannel.Ios.Aps.Alert = Alert{
Title: title,
Body: title,
}
pushReq.PushChannel.Android.Ups.Notification = Notification{
Title: title,
Body: title,
ClickType: "startapp",
}
pushReq.PushChannel.Android.Ups.Options = Options{
HW: struct {
DefaultSound bool `json:"/message/android/notification/default_sound"`
ChannelID string `json:"/message/android/notification/channel_id"`
Sound string `json:"/message/android/notification/sound"`
Importance string `json:"/message/android/notification/importance"`
}{ChannelID: "RingRing4", Sound: "/raw/ring001", Importance: "NORMAL"},
XM: struct {
ChannelID string `json:"/extra.channel_id"`
}{ChannelID: "high_system"},
VV: struct {
Classification int "json:\"/classification\""
}{
Classification: 1,
},
}
}}}
pushReq.setPushChannel(title, detailContent)
pushResp := PushResp{}
err = g.request(PushURL, pushReq, token, &pushResp, operationID)
if len(userIDList) > 1 {
taskID, err := g.GetTaskID(operationID, token, pushReq)
if err != nil {
return "", utils.Wrap(err, "GetTaskIDAndSave2Redis failed")
}
pushReq = PushReq{Audience: &Audience{Alias: userIDList}}
var IsAsync = true
pushReq.IsAsync = &IsAsync
pushReq.Taskid = &taskID
err = g.request(BatchPushURL, pushReq, token, &pushResp, operationID)
} else {
reqID := utils.OperationIDGenerator()
pushReq.RequestID = &reqID
pushReq.Audience = &Audience{Alias: []string{userIDList[0]}}
err = g.request(PushURL, pushReq, token, &pushResp, operationID)
}
switch err {
case TokenExpireError:
token, err = g.getTokenAndSave2Redis(operationID)
@ -209,6 +215,17 @@ func (g *Getui) Auth(operationID string, timeStamp int64) (token string, expireT
return respAuth.Token, int64(expire), err
}
func (g *Getui) GetTaskID(operationID, token string, pushReq PushReq) (string, error) {
respTask := TaskResp{}
ttl := int64(1000 * 60 * 5)
pushReq.Settings = &Settings{TTL: &ttl}
err := g.request(TaskURL, pushReq, token, &respTask, operationID)
if err != nil {
return "", utils.Wrap(err, "")
}
return respTask.TaskID, nil
}
func (g *Getui) request(url string, content interface{}, token string, returnStruct interface{}, operationID string) error {
con, err := json.Marshal(content)
if err != nil {
@ -245,6 +262,41 @@ func (g *Getui) request(url string, content interface{}, token string, returnStr
return nil
}
func (pushReq *PushReq) setPushChannel(title string, body string) {
pushReq.PushChannel = &PushChannel{}
autoBadge := "+1"
pushReq.PushChannel.Ios = &Ios{AutoBadge: &autoBadge}
notify := "notify"
pushReq.PushChannel.Ios.NotiType = &notify
pushReq.PushChannel.Ios.Aps.Sound = "default"
pushReq.PushChannel.Ios.Aps.Alert = Alert{
Title: title,
Body: body,
}
pushReq.PushChannel.Android = &Android{}
pushReq.PushChannel.Android.Ups.Notification = Notification{
Title: title,
Body: body,
ClickType: "startapp",
}
pushReq.PushChannel.Android.Ups.Options = Options{
HW: struct {
DefaultSound bool `json:"/message/android/notification/default_sound"`
ChannelID string `json:"/message/android/notification/channel_id"`
Sound string `json:"/message/android/notification/sound"`
Importance string `json:"/message/android/notification/importance"`
}{ChannelID: "RingRing4", Sound: "/raw/ring001", Importance: "NORMAL"},
XM: struct {
ChannelID string `json:"/extra.channel_id"`
}{ChannelID: "high_system"},
VV: struct {
Classification int "json:\"/classification\""
}{
Classification: 1,
},
}
}
func (g *Getui) getTokenAndSave2Redis(operationID string) (token string, err error) {
token, expireTime, err := g.Auth(operationID, time.Now().UnixNano()/1e6)
if err != nil {
@ -257,3 +309,17 @@ func (g *Getui) getTokenAndSave2Redis(operationID string) (token string, err err
}
return token, nil
}
func (g *Getui) GetTaskIDAndSave2Redis(operationID, token string, pushReq PushReq) (taskID string, err error) {
ttl := int64(1000 * 60 * 60 * 24)
pushReq.Settings = &Settings{TTL: &ttl}
taskID, err = g.GetTaskID(operationID, token, pushReq)
if err != nil {
return "", utils.Wrap(err, "GetTaskIDAndSave2Redis failed")
}
err = db.DB.SetGetuiTaskID(taskID, 60*60*23)
if err != nil {
return "", utils.Wrap(err, "Auth failed")
}
return token, nil
}

View File

@ -75,14 +75,14 @@ func callbackOnlinePush(operationID string, userIDList []string, msg *commonPb.M
},
UserIDList: userIDList,
},
OfflinePushInfo: msg.OfflinePushInfo,
ClientMsgID: msg.ClientMsgID,
SendID: msg.SendID,
GroupID: msg.GroupID,
ContentType: msg.ContentType,
SessionType: msg.SessionType,
AtUserIDList: msg.AtUserIDList,
Content: callback.GetContent(msg),
//OfflinePushInfo: msg.OfflinePushInfo,
ClientMsgID: msg.ClientMsgID,
SendID: msg.SendID,
GroupID: msg.GroupID,
ContentType: msg.ContentType,
SessionType: msg.SessionType,
AtUserIDList: msg.AtUserIDList,
Content: callback.GetContent(msg),
}
resp := &cbApi.CallbackBeforePushResp{CommonCallbackResp: &callbackResp}
if err := http.CallBackPostReturn(config.Config.Callback.CallbackUrl, constant.CallbackOnlinePushCommand, req, resp, config.Config.Callback.CallbackOnlinePush.CallbackTimeOut); err != nil {
@ -97,9 +97,9 @@ func callbackOnlinePush(operationID string, userIDList []string, msg *commonPb.M
}
}
if resp.ErrCode == constant.CallbackHandleSuccess && resp.ActionCode == constant.ActionAllow {
if resp.OfflinePushInfo != nil {
msg.OfflinePushInfo = resp.OfflinePushInfo
}
//if resp.OfflinePushInfo != nil {
// msg.OfflinePushInfo = resp.OfflinePushInfo
//}
}
return callbackResp
}
@ -117,14 +117,15 @@ func callbackBeforeSuperGroupOnlinePush(operationID string, groupID string, msg
PlatformID: msg.SenderPlatformID,
Platform: constant.PlatformIDToName(int(msg.SenderPlatformID)),
},
OfflinePushInfo: msg.OfflinePushInfo,
ClientMsgID: msg.ClientMsgID,
SendID: msg.SendID,
GroupID: groupID,
ContentType: msg.ContentType,
SessionType: msg.SessionType,
AtUserIDList: msg.AtUserIDList,
Content: callback.GetContent(msg),
//OfflinePushInfo: msg.OfflinePushInfo,
ClientMsgID: msg.ClientMsgID,
SendID: msg.SendID,
GroupID: groupID,
ContentType: msg.ContentType,
SessionType: msg.SessionType,
AtUserIDList: msg.AtUserIDList,
Content: callback.GetContent(msg),
Seq: msg.Seq,
}
resp := &cbApi.CallbackBeforeSuperGroupOnlinePushResp{CommonCallbackResp: &callbackResp}
if err := http.CallBackPostReturn(config.Config.Callback.CallbackUrl, constant.CallbackSuperGroupOnlinePushCommand, req, resp, config.Config.Callback.CallbackBeforeSuperGroupOnlinePush.CallbackTimeOut); err != nil {
@ -142,9 +143,9 @@ func callbackBeforeSuperGroupOnlinePush(operationID string, groupID string, msg
if len(resp.UserIDList) != 0 {
*pushToUserList = resp.UserIDList
}
if resp.OfflinePushInfo != nil {
msg.OfflinePushInfo = resp.OfflinePushInfo
}
//if resp.OfflinePushInfo != nil {
// msg.OfflinePushInfo = resp.OfflinePushInfo
//}
}
log.NewDebug(operationID, utils.GetSelfFuncName(), pushToUserList, resp.UserIDList)
return callbackResp

View File

@ -93,10 +93,11 @@ func (r *RPCServer) PushMsg(_ context.Context, pbData *pbPush.PushMsgReq) (*pbPu
}
func (r *RPCServer) DelUserPushToken(c context.Context, req *pbPush.DelUserPushTokenReq) (*pbPush.DelUserPushTokenResp, error) {
log.Debug(req.OperationID, utils.GetSelfFuncName(), "req", req.String())
var resp pbPush.DelUserPushTokenResp
err := db.DB.DelFcmToken(req.UserID, int(req.PlatformID))
if err != nil {
errMsg := req.OperationID + " " + "SetFcmToken failed " + err.Error()
errMsg := req.OperationID + " " + "DelFcmToken failed " + err.Error()
log.NewError(req.OperationID, errMsg)
resp.ErrCode = 500
resp.ErrMsg = errMsg

View File

@ -70,7 +70,7 @@ func MsgToUser(pushMsg *pbPush.PushMsgReq) {
wsResult = append(wsResult, reply.SinglePushResult...)
}
}
log.NewInfo(pushMsg.OperationID, "push_result", wsResult, "sendData", pushMsg.MsgData)
log.NewInfo(pushMsg.OperationID, "push_result", wsResult, "sendData", pushMsg.MsgData, "isOfflinePush", isOfflinePush)
successCount++
if isOfflinePush && pushMsg.PushToUserID != pushMsg.MsgData.SendID {
// save invitation info for offline push
@ -79,6 +79,9 @@ func MsgToUser(pushMsg *pbPush.PushMsgReq) {
return
}
}
if pushMsg.MsgData.ContentType > constant.NotificationBegin && pushMsg.MsgData.ContentType < constant.NotificationEnd && pushMsg.MsgData.ContentType != constant.SignalingNotification {
return
}
if pushMsg.MsgData.ContentType == constant.SignalingNotification {
isSend, err := db.DB.HandleSignalInfo(pushMsg.OperationID, pushMsg.MsgData, pushMsg.PushToUserID)
if err != nil {
@ -198,12 +201,29 @@ func MsgToSuperGroupUser(pushMsg *pbPush.PushMsgReq) {
log.Debug(pushMsg.OperationID, "push_result", wsResult, "sendData", pushMsg.MsgData)
successCount++
if isOfflinePush {
if pushMsg.MsgData.ContentType > constant.NotificationBegin && pushMsg.MsgData.ContentType < constant.NotificationEnd && pushMsg.MsgData.ContentType != constant.SignalingNotification {
return
}
var onlineSuccessUserIDList []string
var WebAndPcBackgroundUserIDList []string
onlineSuccessUserIDList = append(onlineSuccessUserIDList, pushMsg.MsgData.SendID)
for _, v := range wsResult {
if v.OnlinePush && v.UserID != pushMsg.MsgData.SendID {
onlineSuccessUserIDList = append(onlineSuccessUserIDList, v.UserID)
}
if !v.OnlinePush {
if len(v.Resp) != 0 {
for _, singleResult := range v.Resp {
if singleResult.ResultCode == -2 {
if constant.PlatformIDToClass(int(singleResult.RecvPlatFormID)) == constant.TerminalPC ||
singleResult.RecvPlatFormID == constant.WebPlatformID {
WebAndPcBackgroundUserIDList = append(WebAndPcBackgroundUserIDList, v.UserID)
}
}
}
}
}
}
onlineFailedUserIDList := utils.DifferenceString(onlineSuccessUserIDList, pushToUserIDList)
//Use offline push messaging
@ -237,7 +257,7 @@ func MsgToSuperGroupUser(pushMsg *pbPush.PushMsgReq) {
if err != nil {
log.NewError(pushMsg.OperationID, utils.GetSelfFuncName(), "GetOfflinePushOpts failed", pushMsg, err.Error())
}
log.NewInfo(pushMsg.OperationID, utils.GetSelfFuncName(), onlineFailedUserIDList, title, detailContent, "opts:", opts)
log.NewInfo(pushMsg.OperationID, utils.GetSelfFuncName(), needOfflinePushUserIDList, title, detailContent, "opts:", opts)
if title == "" {
switch pushMsg.MsgData.ContentType {
case constant.Text:
@ -274,6 +294,22 @@ func MsgToSuperGroupUser(pushMsg *pbPush.PushMsgReq) {
promePkg.PromeInc(promePkg.MsgOfflinePushSuccessCounter)
log.NewDebug(pushMsg.OperationID, "offline push return result is ", pushResult, pushMsg.MsgData)
}
needBackgroupPushUserID := utils.IntersectString(needOfflinePushUserIDList, WebAndPcBackgroundUserIDList)
grpcCons := getcdv3.GetDefaultGatewayConn4Unique(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), pushMsg.OperationID)
if len(needBackgroupPushUserID) > 0 {
//Online push message
log.Debug(pushMsg.OperationID, "len grpc", len(grpcCons), "data", pushMsg.String())
for _, v := range grpcCons {
msgClient := pbRelay.NewRelayClient(v)
_, err := msgClient.SuperGroupBackgroundOnlinePush(context.Background(), &pbRelay.OnlineBatchPushOneMsgReq{OperationID: pushMsg.OperationID, MsgData: pushMsg.MsgData,
PushToUserIDList: needBackgroupPushUserID})
if err != nil {
log.NewError("push data to client rpc err", pushMsg.OperationID, "err", err)
continue
}
}
}
}
}
}

View File

@ -2,7 +2,7 @@ package push
import "Open_IM/pkg/common/constant"
var PushTerminal = []int{constant.IOSPlatformID, constant.AndroidPlatformID}
var PushTerminal = []int{constant.IOSPlatformID, constant.AndroidPlatformID, constant.WebPlatformID}
type OfflinePusher interface {
Push(userIDList []string, title, detailContent, operationID string, opts PushOpts) (resp string, err error)

View File

@ -133,6 +133,24 @@ func (s *adminCMSServer) AdminLogin(_ context.Context, req *pbAdminCMS.AdminLogi
return resp, nil
}
func (s *adminCMSServer) GetUserToken(_ context.Context, req *pbAdminCMS.GetUserTokenReq) (*pbAdminCMS.GetUserTokenResp, error) {
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String())
resp := &pbAdminCMS.GetUserTokenResp{
CommonResp: &pbAdminCMS.CommonResp{},
}
token, expTime, err := token_verify.CreateToken(req.UserID, int(req.PlatformID))
if err != nil {
log.NewError(req.OperationID, utils.GetSelfFuncName(), "generate token failed", "userID: ", req.UserID, req.PlatformID, err.Error())
resp.CommonResp.ErrCode = constant.ErrTokenUnknown.ErrCode
resp.CommonResp.ErrMsg = err.Error()
return resp, nil
}
resp.Token = token
resp.ExpTime = expTime
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", resp.String())
return resp, nil
}
func (s *adminCMSServer) AddUserRegisterAddFriendIDList(_ context.Context, req *pbAdminCMS.AddUserRegisterAddFriendIDListReq) (*pbAdminCMS.AddUserRegisterAddFriendIDListResp, error) {
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "req: ", req.String())
resp := &pbAdminCMS.AddUserRegisterAddFriendIDListResp{CommonResp: &pbAdminCMS.CommonResp{}}
@ -197,37 +215,50 @@ func (s *adminCMSServer) GetUserRegisterAddFriendIDList(_ context.Context, req *
func (s *adminCMSServer) GetChatLogs(_ context.Context, req *pbAdminCMS.GetChatLogsReq) (*pbAdminCMS.GetChatLogsResp, error) {
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "GetChatLogs", req.String())
resp := &pbAdminCMS.GetChatLogsResp{CommonResp: &pbAdminCMS.CommonResp{}, Pagination: &server_api_params.ResponsePagination{}}
time, err := utils.TimeStringToTime(req.SendTime)
if err != nil {
log.NewError(req.OperationID, utils.GetSelfFuncName(), "time string parse error", err.Error())
resp.CommonResp.ErrCode = constant.ErrArgs.ErrCode
resp.CommonResp.ErrMsg = err.Error()
return resp, nil
}
chatLog := db.ChatLog{
Content: req.Content,
SendTime: time,
ContentType: req.ContentType,
SessionType: req.SessionType,
RecvID: req.RecvID,
SendID: req.SendID,
}
log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "chat_log: ", chatLog)
nums, err := imdb.GetChatLogCount(chatLog)
if err != nil {
log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetChatLogCount", err.Error())
resp.CommonResp.ErrCode = constant.ErrDB.ErrCode
resp.CommonResp.ErrMsg = err.Error()
return resp, nil
if req.SendTime != "" {
sendTime, err := utils.TimeStringToTime(req.SendTime)
if err != nil {
log.NewError(req.OperationID, utils.GetSelfFuncName(), "time string parse error", err.Error())
resp.CommonResp.ErrCode = constant.ErrArgs.ErrCode
resp.CommonResp.ErrMsg = err.Error()
return resp, nil
}
chatLog.SendTime = sendTime
}
resp.ChatLogsNum = int32(nums)
chatLogs, err := imdb.GetChatLog(chatLog, req.Pagination.PageNumber, req.Pagination.ShowNumber)
log.NewDebug(req.OperationID, utils.GetSelfFuncName(), "chat_log: ", chatLog)
num, chatLogs, err := imdb.GetChatLog(&chatLog, req.Pagination.PageNumber, req.Pagination.ShowNumber, []int32{
constant.Text,
constant.Picture,
constant.Voice,
constant.Video,
constant.File,
constant.AtText,
constant.Merger,
constant.Card,
constant.Location,
constant.Custom,
constant.Revoke,
constant.Quote,
constant.AdvancedText,
constant.AdvancedRevoke,
constant.CustomNotTriggerConversation,
})
if err != nil {
log.NewError(req.OperationID, utils.GetSelfFuncName(), "GetChatLog", err.Error())
resp.CommonResp.ErrCode = constant.ErrDB.ErrCode
resp.CommonResp.ErrMsg = err.Error()
return resp, nil
}
resp.ChatLogsNum = int32(num)
for _, chatLog := range chatLogs {
pbChatLog := &pbAdminCMS.ChatLog{}
utils.CopyStructFields(pbChatLog, chatLog)
@ -265,7 +296,6 @@ func (s *adminCMSServer) GetChatLogs(_ context.Context, req *pbAdminCMS.GetChatL
CurrentPage: req.Pagination.PageNumber,
ShowNumber: req.Pagination.ShowNumber,
}
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), "resp output: ", resp.String())
return resp, nil
}

View File

@ -50,6 +50,11 @@ func (rpc *rpcAuth) UserRegister(_ context.Context, req *pbAuth.UserRegisterReq)
func (rpc *rpcAuth) UserToken(_ context.Context, req *pbAuth.UserTokenReq) (*pbAuth.UserTokenResp, error) {
log.NewInfo(req.OperationID, utils.GetSelfFuncName(), " rpc args ", req.String())
_, err := imdb.GetUserByUserID(req.FromUserID)
if err != nil {
log.NewError(req.OperationID, "not this user:", req.FromUserID, req.String())
return &pbAuth.UserTokenResp{CommonResp: &pbAuth.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: err.Error()}}, nil
}
tokens, expTime, err := token_verify.CreateToken(req.FromUserID, int(req.Platform))
if err != nil {
errMsg := req.OperationID + " token_verify.CreateToken failed " + err.Error() + req.FromUserID + utils.Int32ToString(req.Platform)

View File

@ -4,11 +4,14 @@ import (
cbApi "Open_IM/pkg/call_back_struct"
"Open_IM/pkg/common/config"
"Open_IM/pkg/common/constant"
"Open_IM/pkg/common/db"
"Open_IM/pkg/common/http"
"Open_IM/pkg/common/log"
pbGroup "Open_IM/pkg/proto/group"
"Open_IM/pkg/utils"
http2 "net/http"
"google.golang.org/protobuf/types/known/wrapperspb"
)
func callbackBeforeCreateGroup(req *pbGroup.CreateGroupReq) cbApi.CommonCallbackResp {
@ -19,6 +22,9 @@ func callbackBeforeCreateGroup(req *pbGroup.CreateGroupReq) cbApi.CommonCallback
log.NewDebug(req.OperationID, utils.GetSelfFuncName(), req.String())
commonCallbackReq := &cbApi.CallbackBeforeCreateGroupReq{
CallbackCommand: constant.CallbackBeforeCreateGroupCommand,
OperationID: req.OperationID,
GroupInfo: *req.GroupInfo,
InitMemberList: req.InitMemberList,
}
resp := &cbApi.CallbackBeforeCreateGroupResp{
CommonCallbackResp: &callbackResp,
@ -41,7 +47,7 @@ func callbackBeforeCreateGroup(req *pbGroup.CreateGroupReq) cbApi.CommonCallback
req.GroupInfo.GroupID = *resp.GroupID
}
if resp.GroupName != nil {
req.GroupInfo.GroupName = *resp.GroupID
req.GroupInfo.GroupName = *resp.GroupName
}
if resp.Notification != nil {
req.GroupInfo.Notification = *resp.Notification
@ -68,7 +74,7 @@ func callbackBeforeCreateGroup(req *pbGroup.CreateGroupReq) cbApi.CommonCallback
req.GroupInfo.GroupType = *resp.GroupType
}
if resp.NeedVerification != nil {
req.GroupInfo.NeedVerification = *resp.GroupType
req.GroupInfo.NeedVerification = *resp.NeedVerification
}
if resp.LookMemberInfo != nil {
req.GroupInfo.LookMemberInfo = *resp.LookMemberInfo
@ -76,3 +82,102 @@ func callbackBeforeCreateGroup(req *pbGroup.CreateGroupReq) cbApi.CommonCallback
}
return callbackResp
}
func CallbackBeforeMemberJoinGroup(operationID string, groupMember *db.GroupMember, groupEx string) cbApi.CommonCallbackResp {
callbackResp := cbApi.CommonCallbackResp{OperationID: operationID}
if !config.Config.Callback.CallbackBeforeMemberJoinGroup.Enable {
return callbackResp
}
log.NewDebug(operationID, "args: ", *groupMember)
callbackReq := cbApi.CallbackBeforeMemberJoinGroupReq{
CallbackCommand: constant.CallbackBeforeMemberJoinGroupCommand,
OperationID: operationID,
GroupID: groupMember.GroupID,
UserID: groupMember.UserID,
Ex: groupMember.Ex,
GroupEx: groupEx,
}
resp := &cbApi.CallbackBeforeMemberJoinGroupResp{
CommonCallbackResp: &callbackResp,
}
if err := http.CallBackPostReturn(config.Config.Callback.CallbackUrl, constant.CallbackBeforeMemberJoinGroupCommand, callbackReq, resp, config.Config.Callback.CallbackBeforeMemberJoinGroup.CallbackTimeOut); err != nil {
callbackResp.ErrCode = http2.StatusInternalServerError
callbackResp.ErrMsg = err.Error()
if !config.Config.Callback.CallbackBeforeMemberJoinGroup.CallbackFailedContinue {
callbackResp.ActionCode = constant.ActionForbidden
return callbackResp
} else {
callbackResp.ActionCode = constant.ActionAllow
return callbackResp
}
}
if resp.MuteEndTime != nil {
groupMember.MuteEndTime = utils.UnixSecondToTime(*resp.MuteEndTime)
}
if resp.FaceURL != nil {
groupMember.FaceURL = *resp.FaceURL
}
if resp.Ex != nil {
groupMember.Ex = *resp.Ex
}
if resp.NickName != nil {
groupMember.Nickname = *resp.NickName
}
if resp.RoleLevel != nil {
groupMember.RoleLevel = *resp.RoleLevel
}
return callbackResp
}
func CallbackBeforeSetGroupMemberInfo(req *pbGroup.SetGroupMemberInfoReq) cbApi.CommonCallbackResp {
callbackResp := cbApi.CommonCallbackResp{OperationID: req.OperationID}
if !config.Config.Callback.CallbackBeforeSetGroupMemberInfo.Enable {
return callbackResp
}
callbackReq := cbApi.CallbackBeforeSetGroupMemberInfoReq{
CallbackCommand: constant.CallbackBeforeSetGroupMemberInfoCommand,
OperationID: req.OperationID,
GroupID: req.GroupID,
UserID: req.UserID,
}
if req.Nickname != nil {
callbackReq.Nickname = req.Nickname.Value
}
if req.FaceURL != nil {
callbackReq.FaceURL = req.FaceURL.Value
}
if req.RoleLevel != nil {
callbackReq.RoleLevel = req.RoleLevel.Value
}
if req.Ex != nil {
callbackReq.Ex = req.Ex.Value
}
resp := &cbApi.CallbackBeforeSetGroupMemberInfoResp{
CommonCallbackResp: &callbackResp,
}
if err := http.CallBackPostReturn(config.Config.Callback.CallbackUrl, constant.CallbackBeforeSetGroupMemberInfoCommand, callbackReq, resp, config.Config.Callback.CallbackBeforeSetGroupMemberInfo.CallbackTimeOut); err != nil {
callbackResp.ErrCode = http2.StatusInternalServerError
callbackResp.ErrMsg = err.Error()
if !config.Config.Callback.CallbackBeforeSetGroupMemberInfo.CallbackFailedContinue {
callbackResp.ActionCode = constant.ActionForbidden
return callbackResp
} else {
callbackResp.ActionCode = constant.ActionAllow
return callbackResp
}
}
if resp.FaceURL != nil {
req.FaceURL = &wrapperspb.StringValue{Value: *resp.FaceURL}
}
if resp.Nickname != nil {
req.Nickname = &wrapperspb.StringValue{Value: *resp.Nickname}
}
if resp.RoleLevel != nil {
req.RoleLevel = &wrapperspb.Int32Value{Value: *resp.RoleLevel}
}
if resp.Ex != nil {
req.Ex = &wrapperspb.StringValue{Value: *resp.Ex}
}
return callbackResp
}

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,7 @@ import (
commonPb "Open_IM/pkg/proto/sdk_ws"
"Open_IM/pkg/utils"
"context"
"github.com/go-redis/redis/v8"
)

View File

@ -0,0 +1,435 @@
package msg
import (
"Open_IM/pkg/common/constant"
"Open_IM/pkg/common/db"
"Open_IM/pkg/common/log"
"Open_IM/pkg/proto/msg"
"Open_IM/pkg/proto/sdk_ws"
"Open_IM/pkg/utils"
"context"
go_redis "github.com/go-redis/redis/v8"
"time"
)
func (rpc *rpcChat) SetMessageReactionExtensions(ctx context.Context, req *msg.SetMessageReactionExtensionsReq) (resp *msg.SetMessageReactionExtensionsResp, err error) {
log.Debug(req.OperationID, utils.GetSelfFuncName(), "rpc args is:", req.String())
var rResp msg.SetMessageReactionExtensionsResp
rResp.ClientMsgID = req.ClientMsgID
rResp.MsgFirstModifyTime = req.MsgFirstModifyTime
callbackResp := callbackSetMessageReactionExtensions(req)
if callbackResp.ActionCode != constant.ActionAllow || callbackResp.ErrCode != 0 {
rResp.ErrCode = int32(callbackResp.ErrCode)
rResp.ErrMsg = callbackResp.ErrMsg
for _, value := range req.ReactionExtensionList {
temp := new(msg.KeyValueResp)
temp.KeyValue = value
temp.ErrMsg = callbackResp.ErrMsg
temp.ErrCode = 100
rResp.Result = append(rResp.Result, temp)
}
return &rResp, nil
}
//if ExternalExtension
if req.IsExternalExtensions {
var isHistory bool
if req.IsReact {
isHistory = false
} else {
isHistory = true
}
rResp.MsgFirstModifyTime = callbackResp.MsgFirstModifyTime
rResp.Result = callbackResp.ResultReactionExtensionList
ExtendMessageUpdatedNotification(req.OperationID, req.OpUserID, req.SourceID, req.SessionType, req, &rResp, isHistory, false)
return &rResp, nil
}
for _, v := range callbackResp.ResultReactionExtensionList {
if v.ErrCode == 0 {
req.ReactionExtensionList[v.KeyValue.TypeKey] = v.KeyValue
} else {
delete(req.ReactionExtensionList, v.KeyValue.TypeKey)
rResp.Result = append(rResp.Result, v)
}
}
isExists, err := db.DB.JudgeMessageReactionEXISTS(req.ClientMsgID, req.SessionType)
if err != nil {
rResp.ErrCode = 100
rResp.ErrMsg = err.Error()
for _, value := range req.ReactionExtensionList {
temp := new(msg.KeyValueResp)
temp.KeyValue = value
temp.ErrMsg = err.Error()
temp.ErrCode = 100
rResp.Result = append(rResp.Result, temp)
}
return &rResp, nil
}
if !isExists {
if !req.IsReact {
log.Debug(req.OperationID, "redis handle firstly", req.String())
rResp.MsgFirstModifyTime = utils.GetCurrentTimestampByMill()
for k, v := range req.ReactionExtensionList {
err := rpc.dMessageLocker.LockMessageTypeKey(req.ClientMsgID, k)
if err != nil {
setKeyResultInfo(&rResp, 100, err.Error(), req.ClientMsgID, k, v)
continue
}
v.LatestUpdateTime = utils.GetCurrentTimestampByMill()
newerr := db.DB.SetMessageTypeKeyValue(req.ClientMsgID, req.SessionType, k, utils.StructToJsonString(v))
if newerr != nil {
setKeyResultInfo(&rResp, 201, newerr.Error(), req.ClientMsgID, k, v)
continue
}
setKeyResultInfo(&rResp, 0, "", req.ClientMsgID, k, v)
}
rResp.IsReact = true
_, err := db.DB.SetMessageReactionExpire(req.ClientMsgID, req.SessionType, time.Duration(24*3)*time.Hour)
if err != nil {
log.Error(req.OperationID, "SetMessageReactionExpire err:", err.Error(), req.String())
}
} else {
err := rpc.dMessageLocker.LockGlobalMessage(req.ClientMsgID)
if err != nil {
rResp.ErrCode = 100
rResp.ErrMsg = err.Error()
for _, value := range req.ReactionExtensionList {
temp := new(msg.KeyValueResp)
temp.KeyValue = value
temp.ErrMsg = err.Error()
temp.ErrCode = 100
rResp.Result = append(rResp.Result, temp)
}
return &rResp, nil
}
mongoValue, err := db.DB.GetExtendMsg(req.SourceID, req.SessionType, req.ClientMsgID, req.MsgFirstModifyTime)
if err != nil {
rResp.ErrCode = 200
rResp.ErrMsg = err.Error()
for _, value := range req.ReactionExtensionList {
temp := new(msg.KeyValueResp)
temp.KeyValue = value
temp.ErrMsg = err.Error()
temp.ErrCode = 100
rResp.Result = append(rResp.Result, temp)
}
return &rResp, nil
}
setValue := make(map[string]*server_api_params.KeyValue)
for k, v := range req.ReactionExtensionList {
temp := new(server_api_params.KeyValue)
if vv, ok := mongoValue.ReactionExtensionList[k]; ok {
utils.CopyStructFields(temp, &vv)
if v.LatestUpdateTime != vv.LatestUpdateTime {
setKeyResultInfo(&rResp, 300, "message have update", req.ClientMsgID, k, temp)
continue
}
}
temp.TypeKey = k
temp.Value = v.Value
temp.LatestUpdateTime = utils.GetCurrentTimestampByMill()
setValue[k] = temp
}
err = db.DB.InsertOrUpdateReactionExtendMsgSet(req.SourceID, req.SessionType, req.ClientMsgID, req.MsgFirstModifyTime, setValue)
if err != nil {
for _, value := range setValue {
temp := new(msg.KeyValueResp)
temp.KeyValue = value
temp.ErrMsg = err.Error()
temp.ErrCode = 100
rResp.Result = append(rResp.Result, temp)
}
} else {
for _, value := range setValue {
temp := new(msg.KeyValueResp)
temp.KeyValue = value
rResp.Result = append(rResp.Result, temp)
}
}
lockErr := rpc.dMessageLocker.UnLockGlobalMessage(req.ClientMsgID)
if lockErr != nil {
log.Error(req.OperationID, "UnLockGlobalMessage err:", lockErr.Error())
}
}
} else {
log.Debug(req.OperationID, "redis handle secondly", req.String())
for k, v := range req.ReactionExtensionList {
err := rpc.dMessageLocker.LockMessageTypeKey(req.ClientMsgID, k)
if err != nil {
setKeyResultInfo(&rResp, 100, err.Error(), req.ClientMsgID, k, v)
continue
}
redisValue, err := db.DB.GetMessageTypeKeyValue(req.ClientMsgID, req.SessionType, k)
if err != nil && err != go_redis.Nil {
setKeyResultInfo(&rResp, 200, err.Error(), req.ClientMsgID, k, v)
continue
}
temp := new(server_api_params.KeyValue)
utils.JsonStringToStruct(redisValue, temp)
if v.LatestUpdateTime != temp.LatestUpdateTime {
setKeyResultInfo(&rResp, 300, "message have update", req.ClientMsgID, k, temp)
continue
} else {
v.LatestUpdateTime = utils.GetCurrentTimestampByMill()
newerr := db.DB.SetMessageTypeKeyValue(req.ClientMsgID, req.SessionType, k, utils.StructToJsonString(v))
if newerr != nil {
setKeyResultInfo(&rResp, 201, newerr.Error(), req.ClientMsgID, k, temp)
continue
}
setKeyResultInfo(&rResp, 0, "", req.ClientMsgID, k, v)
}
}
}
if !isExists {
if !req.IsReact {
ExtendMessageUpdatedNotification(req.OperationID, req.OpUserID, req.SourceID, req.SessionType, req, &rResp, true, true)
} else {
ExtendMessageUpdatedNotification(req.OperationID, req.OpUserID, req.SourceID, req.SessionType, req, &rResp, false, false)
}
} else {
ExtendMessageUpdatedNotification(req.OperationID, req.OpUserID, req.SourceID, req.SessionType, req, &rResp, false, true)
}
log.Debug(req.OperationID, utils.GetSelfFuncName(), "rpc return is:", rResp.String())
return &rResp, nil
}
func setKeyResultInfo(r *msg.SetMessageReactionExtensionsResp, errCode int32, errMsg, clientMsgID, typeKey string, keyValue *server_api_params.KeyValue) {
temp := new(msg.KeyValueResp)
temp.KeyValue = keyValue
temp.ErrCode = errCode
temp.ErrMsg = errMsg
r.Result = append(r.Result, temp)
_ = db.DB.UnLockMessageTypeKey(clientMsgID, typeKey)
}
func setDeleteKeyResultInfo(r *msg.DeleteMessageListReactionExtensionsResp, errCode int32, errMsg, clientMsgID, typeKey string, keyValue *server_api_params.KeyValue) {
temp := new(msg.KeyValueResp)
temp.KeyValue = keyValue
temp.ErrCode = errCode
temp.ErrMsg = errMsg
r.Result = append(r.Result, temp)
_ = db.DB.UnLockMessageTypeKey(clientMsgID, typeKey)
}
func (rpc *rpcChat) GetMessageListReactionExtensions(ctx context.Context, req *msg.GetMessageListReactionExtensionsReq) (resp *msg.GetMessageListReactionExtensionsResp, err error) {
log.Debug(req.OperationID, utils.GetSelfFuncName(), "rpc args is:", req.String())
var rResp msg.GetMessageListReactionExtensionsResp
if req.IsExternalExtensions {
callbackResp := callbackGetMessageListReactionExtensions(req)
if callbackResp.ActionCode != constant.ActionAllow || callbackResp.ErrCode != 0 {
rResp.ErrCode = int32(callbackResp.ErrCode)
rResp.ErrMsg = callbackResp.ErrMsg
return &rResp, nil
} else {
rResp.SingleMessageResult = callbackResp.MessageResultList
return &rResp, nil
}
}
for _, messageValue := range req.MessageReactionKeyList {
var oneMessage msg.SingleMessageExtensionResult
oneMessage.ClientMsgID = messageValue.ClientMsgID
isExists, err := db.DB.JudgeMessageReactionEXISTS(messageValue.ClientMsgID, req.SessionType)
if err != nil {
rResp.ErrCode = 100
rResp.ErrMsg = err.Error()
return &rResp, nil
}
if isExists {
redisValue, err := db.DB.GetOneMessageAllReactionList(messageValue.ClientMsgID, req.SessionType)
if err != nil {
oneMessage.ErrCode = 100
oneMessage.ErrMsg = err.Error()
rResp.SingleMessageResult = append(rResp.SingleMessageResult, &oneMessage)
continue
}
keyMap := make(map[string]*server_api_params.KeyValue)
for k, v := range redisValue {
temp := new(server_api_params.KeyValue)
utils.JsonStringToStruct(v, temp)
keyMap[k] = temp
}
oneMessage.ReactionExtensionList = keyMap
} else {
mongoValue, err := db.DB.GetExtendMsg(req.SourceID, req.SessionType, messageValue.ClientMsgID, messageValue.MsgFirstModifyTime)
if err != nil {
oneMessage.ErrCode = 100
oneMessage.ErrMsg = err.Error()
rResp.SingleMessageResult = append(rResp.SingleMessageResult, &oneMessage)
continue
}
keyMap := make(map[string]*server_api_params.KeyValue)
for k, v := range mongoValue.ReactionExtensionList {
temp := new(server_api_params.KeyValue)
temp.TypeKey = v.TypeKey
temp.Value = v.Value
temp.LatestUpdateTime = v.LatestUpdateTime
keyMap[k] = temp
}
oneMessage.ReactionExtensionList = keyMap
}
rResp.SingleMessageResult = append(rResp.SingleMessageResult, &oneMessage)
}
log.Debug(req.OperationID, utils.GetSelfFuncName(), "rpc return is:", rResp.String())
return &rResp, nil
}
func (rpc *rpcChat) AddMessageReactionExtensions(ctx context.Context, req *msg.ModifyMessageReactionExtensionsReq) (resp *msg.ModifyMessageReactionExtensionsResp, err error) {
return
}
func (rpc *rpcChat) DeleteMessageReactionExtensions(ctx context.Context, req *msg.DeleteMessageListReactionExtensionsReq) (resp *msg.DeleteMessageListReactionExtensionsResp, err error) {
log.Debug(req.OperationID, utils.GetSelfFuncName(), "rpc args is:", req.String())
var rResp msg.DeleteMessageListReactionExtensionsResp
callbackResp := callbackDeleteMessageReactionExtensions(req)
if callbackResp.ActionCode != constant.ActionAllow || callbackResp.ErrCode != 0 {
rResp.ErrCode = int32(callbackResp.ErrCode)
rResp.ErrMsg = callbackResp.ErrMsg
for _, value := range req.ReactionExtensionList {
temp := new(msg.KeyValueResp)
temp.KeyValue = value
temp.ErrMsg = callbackResp.ErrMsg
temp.ErrCode = 100
rResp.Result = append(rResp.Result, temp)
}
return &rResp, nil
}
//if ExternalExtension
if req.IsExternalExtensions {
rResp.Result = callbackResp.ResultReactionExtensionList
ExtendMessageDeleteNotification(req.OperationID, req.OpUserID, req.SourceID, req.SessionType, req, &rResp, false, false)
return &rResp, nil
}
for _, v := range callbackResp.ResultReactionExtensionList {
if v.ErrCode != 0 {
func(req *[]*server_api_params.KeyValue, typeKey string) {
for i := 0; i < len(*req); i++ {
if (*req)[i].TypeKey == typeKey {
*req = append((*req)[:i], (*req)[i+1:]...)
}
}
}(&req.ReactionExtensionList, v.KeyValue.TypeKey)
rResp.Result = append(rResp.Result, v)
}
}
isExists, err := db.DB.JudgeMessageReactionEXISTS(req.ClientMsgID, req.SessionType)
if err != nil {
rResp.ErrCode = 100
rResp.ErrMsg = err.Error()
for _, value := range req.ReactionExtensionList {
temp := new(msg.KeyValueResp)
temp.KeyValue = value
temp.ErrMsg = err.Error()
temp.ErrCode = 100
rResp.Result = append(rResp.Result, temp)
}
return &rResp, nil
}
if isExists {
log.Debug(req.OperationID, "redis handle this delete", req.String())
for _, v := range req.ReactionExtensionList {
err := rpc.dMessageLocker.LockMessageTypeKey(req.ClientMsgID, v.TypeKey)
if err != nil {
setDeleteKeyResultInfo(&rResp, 100, err.Error(), req.ClientMsgID, v.TypeKey, v)
continue
}
redisValue, err := db.DB.GetMessageTypeKeyValue(req.ClientMsgID, req.SessionType, v.TypeKey)
if err != nil && err != go_redis.Nil {
setDeleteKeyResultInfo(&rResp, 200, err.Error(), req.ClientMsgID, v.TypeKey, v)
continue
}
temp := new(server_api_params.KeyValue)
utils.JsonStringToStruct(redisValue, temp)
if v.LatestUpdateTime != temp.LatestUpdateTime {
setDeleteKeyResultInfo(&rResp, 300, "message have update", req.ClientMsgID, v.TypeKey, temp)
continue
} else {
newErr := db.DB.DeleteOneMessageKey(req.ClientMsgID, req.SessionType, v.TypeKey)
if newErr != nil {
setDeleteKeyResultInfo(&rResp, 201, newErr.Error(), req.ClientMsgID, v.TypeKey, temp)
continue
}
setDeleteKeyResultInfo(&rResp, 0, "", req.ClientMsgID, v.TypeKey, v)
}
}
} else {
err := rpc.dMessageLocker.LockGlobalMessage(req.ClientMsgID)
if err != nil {
rResp.ErrCode = 100
rResp.ErrMsg = err.Error()
for _, value := range req.ReactionExtensionList {
temp := new(msg.KeyValueResp)
temp.KeyValue = value
temp.ErrMsg = err.Error()
temp.ErrCode = 100
rResp.Result = append(rResp.Result, temp)
}
return &rResp, nil
}
mongoValue, err := db.DB.GetExtendMsg(req.SourceID, req.SessionType, req.ClientMsgID, req.MsgFirstModifyTime)
if err != nil {
rResp.ErrCode = 200
rResp.ErrMsg = err.Error()
for _, value := range req.ReactionExtensionList {
temp := new(msg.KeyValueResp)
temp.KeyValue = value
temp.ErrMsg = err.Error()
temp.ErrCode = 100
rResp.Result = append(rResp.Result, temp)
}
return &rResp, nil
}
setValue := make(map[string]*server_api_params.KeyValue)
for _, v := range req.ReactionExtensionList {
temp := new(server_api_params.KeyValue)
if vv, ok := mongoValue.ReactionExtensionList[v.TypeKey]; ok {
utils.CopyStructFields(temp, &vv)
if v.LatestUpdateTime != vv.LatestUpdateTime {
setDeleteKeyResultInfo(&rResp, 300, "message have update", req.ClientMsgID, v.TypeKey, temp)
continue
}
} else {
setDeleteKeyResultInfo(&rResp, 400, "key not in", req.ClientMsgID, v.TypeKey, v)
continue
}
temp.TypeKey = v.TypeKey
setValue[v.TypeKey] = temp
}
err = db.DB.DeleteReactionExtendMsgSet(req.SourceID, req.SessionType, req.ClientMsgID, req.MsgFirstModifyTime, setValue)
if err != nil {
for _, value := range setValue {
temp := new(msg.KeyValueResp)
temp.KeyValue = value
temp.ErrMsg = err.Error()
temp.ErrCode = 100
rResp.Result = append(rResp.Result, temp)
}
} else {
for _, value := range setValue {
temp := new(msg.KeyValueResp)
temp.KeyValue = value
rResp.Result = append(rResp.Result, temp)
}
}
lockErr := rpc.dMessageLocker.UnLockGlobalMessage(req.ClientMsgID)
if lockErr != nil {
log.Error(req.OperationID, "UnLockGlobalMessage err:", lockErr.Error())
}
}
ExtendMessageDeleteNotification(req.OperationID, req.OpUserID, req.SourceID, req.SessionType, req, &rResp, false, isExists)
log.Debug(req.OperationID, utils.GetSelfFuncName(), "rpc return is:", rResp.String())
return &rResp, nil
}

View File

@ -0,0 +1,106 @@
package msg
import (
"Open_IM/pkg/base_info"
"Open_IM/pkg/common/config"
"Open_IM/pkg/common/constant"
"Open_IM/pkg/common/log"
"Open_IM/pkg/grpc-etcdv3/getcdv3"
"Open_IM/pkg/proto/msg"
open_im_sdk "Open_IM/pkg/proto/sdk_ws"
"Open_IM/pkg/utils"
"context"
"strings"
)
func ExtendMessageUpdatedNotification(operationID, sendID string, sourceID string, sessionType int32,
req *msg.SetMessageReactionExtensionsReq, resp *msg.SetMessageReactionExtensionsResp, isHistory bool, isReactionFromCache bool) {
var m base_info.ReactionMessageModifierNotification
m.SourceID = req.SourceID
m.OpUserID = req.OpUserID
m.SessionType = req.SessionType
keyMap := make(map[string]*open_im_sdk.KeyValue)
for _, valueResp := range resp.Result {
if valueResp.ErrCode == 0 {
keyMap[valueResp.KeyValue.TypeKey] = valueResp.KeyValue
}
}
if len(keyMap) == 0 {
log.NewWarn(operationID, "all key set failed can not send notification", *req)
return
}
m.SuccessReactionExtensionList = keyMap
m.ClientMsgID = req.ClientMsgID
m.IsReact = resp.IsReact
m.IsExternalExtensions = req.IsExternalExtensions
m.MsgFirstModifyTime = resp.MsgFirstModifyTime
messageReactionSender(operationID, sendID, sourceID, sessionType, constant.ReactionMessageModifier, utils.StructToJsonString(m), isHistory, isReactionFromCache)
}
func ExtendMessageDeleteNotification(operationID, sendID string, sourceID string, sessionType int32,
req *msg.DeleteMessageListReactionExtensionsReq, resp *msg.DeleteMessageListReactionExtensionsResp, isHistory bool, isReactionFromCache bool) {
var m base_info.ReactionMessageDeleteNotification
m.SourceID = req.SourceID
m.OpUserID = req.OpUserID
m.SessionType = req.SessionType
keyMap := make(map[string]*open_im_sdk.KeyValue)
for _, valueResp := range resp.Result {
if valueResp.ErrCode == 0 {
keyMap[valueResp.KeyValue.TypeKey] = valueResp.KeyValue
}
}
if len(keyMap) == 0 {
log.NewWarn(operationID, "all key set failed can not send notification", *req)
return
}
m.SuccessReactionExtensionList = keyMap
m.ClientMsgID = req.ClientMsgID
m.MsgFirstModifyTime = req.MsgFirstModifyTime
messageReactionSender(operationID, sendID, sourceID, sessionType, constant.ReactionMessageDeleter, utils.StructToJsonString(m), isHistory, isReactionFromCache)
}
func messageReactionSender(operationID, sendID string, sourceID string, sessionType, contentType int32, content string, isHistory bool, isReactionFromCache bool) {
options := make(map[string]bool, 5)
utils.SetSwitchFromOptions(options, constant.IsOfflinePush, false)
utils.SetSwitchFromOptions(options, constant.IsConversationUpdate, false)
utils.SetSwitchFromOptions(options, constant.IsSenderConversationUpdate, false)
utils.SetSwitchFromOptions(options, constant.IsUnreadCount, false)
utils.SetSwitchFromOptions(options, constant.IsReactionFromCache, isReactionFromCache)
if !isHistory {
utils.SetSwitchFromOptions(options, constant.IsHistory, false)
utils.SetSwitchFromOptions(options, constant.IsPersistent, false)
}
pbData := msg.SendMsgReq{
OperationID: operationID,
MsgData: &open_im_sdk.MsgData{
SendID: sendID,
ClientMsgID: utils.GetMsgID(sendID),
SessionType: sessionType,
MsgFrom: constant.SysMsgType,
ContentType: contentType,
Content: []byte(content),
// ForceList: params.ForceList,
CreateTime: utils.GetCurrentTimestampByMill(),
Options: options,
},
}
switch sessionType {
case constant.SingleChatType, constant.NotificationChatType:
pbData.MsgData.RecvID = sourceID
case constant.GroupChatType, constant.SuperGroupChatType:
pbData.MsgData.GroupID = sourceID
}
etcdConn := getcdv3.GetDefaultConn(config.Config.Etcd.EtcdSchema, strings.Join(config.Config.Etcd.EtcdAddr, ","), config.Config.RpcRegisterName.OpenImMsgName, operationID)
if etcdConn == nil {
errMsg := operationID + "getcdv3.GetDefaultConn == nil"
log.NewError(operationID, errMsg)
return
}
client := msg.NewMsgClient(etcdConn)
reply, err := client.SendMsg(context.Background(), &pbData)
if err != nil {
log.NewError(operationID, "SendMsg rpc failed, ", pbData.String(), err.Error())
} else if reply.ErrCode != 0 {
log.NewError(operationID, "SendMsg rpc failed, ", pbData.String(), reply.ErrCode, reply.ErrMsg)
}
}

View File

@ -0,0 +1,79 @@
package msg
import (
cbApi "Open_IM/pkg/call_back_struct"
"Open_IM/pkg/common/config"
"Open_IM/pkg/common/constant"
"Open_IM/pkg/common/http"
"Open_IM/pkg/common/log"
"Open_IM/pkg/proto/msg"
"Open_IM/pkg/utils"
http2 "net/http"
)
func callbackSetMessageReactionExtensions(setReq *msg.SetMessageReactionExtensionsReq) *cbApi.CallbackBeforeSetMessageReactionExtResp {
callbackResp := cbApi.CommonCallbackResp{OperationID: setReq.OperationID}
log.NewDebug(setReq.OperationID, utils.GetSelfFuncName(), setReq.String())
req := cbApi.CallbackBeforeSetMessageReactionExtReq{
OperationID: setReq.OperationID,
CallbackCommand: constant.CallbackBeforeSetMessageReactionExtensionCommand,
SourceID: setReq.SourceID,
OpUserID: setReq.OpUserID,
SessionType: setReq.SessionType,
ReactionExtensionList: setReq.ReactionExtensionList,
ClientMsgID: setReq.ClientMsgID,
IsReact: setReq.IsReact,
IsExternalExtensions: setReq.IsExternalExtensions,
MsgFirstModifyTime: setReq.MsgFirstModifyTime,
}
resp := &cbApi.CallbackBeforeSetMessageReactionExtResp{CommonCallbackResp: &callbackResp}
defer log.NewDebug(setReq.OperationID, utils.GetSelfFuncName(), req, *resp)
if err := http.CallBackPostReturn(config.Config.Callback.CallbackUrl, constant.CallbackBeforeSetMessageReactionExtensionCommand, req, resp, config.Config.Callback.CallbackAfterSendGroupMsg.CallbackTimeOut); err != nil {
callbackResp.ErrCode = http2.StatusInternalServerError
callbackResp.ErrMsg = err.Error()
}
return resp
}
func callbackDeleteMessageReactionExtensions(setReq *msg.DeleteMessageListReactionExtensionsReq) *cbApi.CallbackDeleteMessageReactionExtResp {
callbackResp := cbApi.CommonCallbackResp{OperationID: setReq.OperationID}
log.NewDebug(setReq.OperationID, utils.GetSelfFuncName(), setReq.String())
req := cbApi.CallbackDeleteMessageReactionExtReq{
OperationID: setReq.OperationID,
CallbackCommand: constant.CallbackBeforeDeleteMessageReactionExtensionsCommand,
SourceID: setReq.SourceID,
OpUserID: setReq.OpUserID,
SessionType: setReq.SessionType,
ReactionExtensionList: setReq.ReactionExtensionList,
ClientMsgID: setReq.ClientMsgID,
IsExternalExtensions: setReq.IsExternalExtensions,
MsgFirstModifyTime: setReq.MsgFirstModifyTime,
}
resp := &cbApi.CallbackDeleteMessageReactionExtResp{CommonCallbackResp: &callbackResp}
defer log.NewDebug(setReq.OperationID, utils.GetSelfFuncName(), req, *resp)
if err := http.CallBackPostReturn(config.Config.Callback.CallbackUrl, constant.CallbackBeforeDeleteMessageReactionExtensionsCommand, req, resp, config.Config.Callback.CallbackAfterSendGroupMsg.CallbackTimeOut); err != nil {
callbackResp.ErrCode = http2.StatusInternalServerError
callbackResp.ErrMsg = err.Error()
}
return resp
}
func callbackGetMessageListReactionExtensions(setReq *msg.GetMessageListReactionExtensionsReq) *cbApi.CallbackGetMessageListReactionExtResp {
callbackResp := cbApi.CommonCallbackResp{OperationID: setReq.OperationID}
log.NewDebug(setReq.OperationID, utils.GetSelfFuncName(), setReq.String())
req := cbApi.CallbackGetMessageListReactionExtReq{
OperationID: setReq.OperationID,
CallbackCommand: constant.CallbackGetMessageListReactionExtensionsCommand,
SourceID: setReq.SourceID,
OpUserID: setReq.OpUserID,
SessionType: setReq.SessionType,
MessageKeyList: setReq.MessageReactionKeyList,
}
resp := &cbApi.CallbackGetMessageListReactionExtResp{CommonCallbackResp: &callbackResp}
defer log.NewDebug(setReq.OperationID, utils.GetSelfFuncName(), req, *resp)
if err := http.CallBackPostReturn(config.Config.Callback.CallbackUrl, constant.CallbackGetMessageListReactionExtensionsCommand, req, resp, config.Config.Callback.CallbackAfterSendGroupMsg.CallbackTimeOut); err != nil {
callbackResp.ErrCode = http2.StatusInternalServerError
callbackResp.ErrMsg = err.Error()
}
return resp
}

View File

@ -68,6 +68,8 @@ func friendNotification(commID *pbFriend.CommID, contentType int32, m proto.Mess
tips.DefaultTips = cn.BlackDeleted.DefaultTips.Tips + toUserNickname
case constant.UserInfoUpdatedNotification:
tips.DefaultTips = cn.UserInfoUpdated.DefaultTips.Tips
case constant.FriendInfoUpdatedNotification:
tips.DefaultTips = cn.FriendInfoUpdated.DefaultTips.Tips + toUserNickname
default:
log.Error(commID.OperationID, "contentType failed ", contentType)
return
@ -158,8 +160,15 @@ func BlackDeletedNotification(req *pbFriend.RemoveBlacklistReq) {
friendNotification(req.CommID, constant.BlackDeletedNotification, &blackDeletedTips)
}
func UserInfoUpdatedNotification(operationID, userID string, needNotifiedUserID string) {
selfInfoUpdatedTips := open_im_sdk.UserInfoUpdatedTips{UserID: userID}
commID := pbFriend.CommID{FromUserID: userID, ToUserID: needNotifiedUserID, OpUserID: userID, OperationID: operationID}
//send to myself
func UserInfoUpdatedNotification(operationID, opUserID string, changedUserID string) {
selfInfoUpdatedTips := open_im_sdk.UserInfoUpdatedTips{UserID: changedUserID}
commID := pbFriend.CommID{FromUserID: opUserID, ToUserID: changedUserID, OpUserID: opUserID, OperationID: operationID}
friendNotification(&commID, constant.UserInfoUpdatedNotification, &selfInfoUpdatedTips)
}
func FriendInfoUpdatedNotification(operationID, changedUserID string, needNotifiedUserID string, opUserID string) {
selfInfoUpdatedTips := open_im_sdk.UserInfoUpdatedTips{UserID: changedUserID}
commID := pbFriend.CommID{FromUserID: opUserID, ToUserID: needNotifiedUserID, OpUserID: opUserID, OperationID: operationID}
friendNotification(&commID, constant.FriendInfoUpdatedNotification, &selfInfoUpdatedTips)
}

View File

@ -416,8 +416,6 @@ func MemberQuitNotification(req *pbGroup.QuitGroupReq) {
}
groupNotification(constant.MemberQuitNotification, &MemberQuitTips, req.OpUserID, req.GroupID, "", req.OperationID)
// groupNotification(constant.MemberQuitNotification, &MemberQuitTips, req.OpUserID, "", req.OpUserID, req.OperationID)
}
//message ApplicationProcessedTips{
@ -437,7 +435,20 @@ func GroupApplicationAcceptedNotification(req *pbGroup.GroupApplicationResponseR
log.Error(req.OperationID, "setOpUserInfo failed", req.OpUserID, req.GroupID, GroupApplicationAcceptedTips.OpUser)
return
}
groupNotification(constant.GroupApplicationAcceptedNotification, &GroupApplicationAcceptedTips, req.OpUserID, "", req.FromUserID, req.OperationID)
adminList, err := imdb.GetOwnerManagerByGroupID(req.GroupID)
if err != nil {
log.Error(req.OperationID, "GetOwnerManagerByGroupID failed", req.GroupID)
return
}
for _, v := range adminList {
if v.UserID == req.OpUserID {
continue
}
GroupApplicationAcceptedTips.ReceiverAs = 1
groupNotification(constant.GroupApplicationAcceptedNotification, &GroupApplicationAcceptedTips, req.OpUserID, "", v.UserID, req.OperationID)
}
}
func GroupApplicationRejectedNotification(req *pbGroup.GroupApplicationResponseReq) {
@ -451,6 +462,18 @@ func GroupApplicationRejectedNotification(req *pbGroup.GroupApplicationResponseR
return
}
groupNotification(constant.GroupApplicationRejectedNotification, &GroupApplicationRejectedTips, req.OpUserID, "", req.FromUserID, req.OperationID)
adminList, err := imdb.GetOwnerManagerByGroupID(req.GroupID)
if err != nil {
log.Error(req.OperationID, "GetOwnerManagerByGroupID failed", req.GroupID)
return
}
for _, v := range adminList {
if v.UserID == req.OpUserID {
continue
}
GroupApplicationRejectedTips.ReceiverAs = 1
groupNotification(constant.GroupApplicationRejectedNotification, &GroupApplicationRejectedTips, req.OpUserID, "", v.UserID, req.OperationID)
}
}
func GroupOwnerTransferredNotification(req *pbGroup.TransferGroupOwnerReq) {

52
internal/rpc/msg/lock.go Normal file
View File

@ -0,0 +1,52 @@
package msg
import (
"Open_IM/pkg/common/db"
"time"
)
const GlOBLLOCK = "GLOBAL_LOCK"
type MessageLocker interface {
LockMessageTypeKey(clientMsgID, typeKey string) (err error)
UnLockMessageTypeKey(clientMsgID string, typeKey string) error
LockGlobalMessage(clientMsgID string) (err error)
UnLockGlobalMessage(clientMsgID string) (err error)
}
type LockerMessage struct{}
func NewLockerMessage() *LockerMessage {
return &LockerMessage{}
}
func (l *LockerMessage) LockMessageTypeKey(clientMsgID, typeKey string) (err error) {
for i := 0; i < 3; i++ {
err = db.DB.LockMessageTypeKey(clientMsgID, typeKey)
if err != nil {
time.Sleep(time.Millisecond * 100)
continue
} else {
break
}
}
return err
}
func (l *LockerMessage) LockGlobalMessage(clientMsgID string) (err error) {
for i := 0; i < 3; i++ {
err = db.DB.LockMessageTypeKey(clientMsgID, GlOBLLOCK)
if err != nil {
time.Sleep(time.Millisecond * 100)
continue
} else {
break
}
}
return err
}
func (l *LockerMessage) UnLockMessageTypeKey(clientMsgID string, typeKey string) error {
return db.DB.UnLockMessageTypeKey(clientMsgID, typeKey)
}
func (l *LockerMessage) UnLockGlobalMessage(clientMsgID string) error {
return db.DB.UnLockMessageTypeKey(clientMsgID, GlOBLLOCK)
}

View File

@ -10,11 +10,12 @@ import (
"Open_IM/pkg/grpc-etcdv3/getcdv3"
"Open_IM/pkg/proto/msg"
"Open_IM/pkg/utils"
"github.com/golang/protobuf/proto"
"net"
"strconv"
"strings"
"github.com/golang/protobuf/proto"
grpcPrometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
"google.golang.org/grpc"
@ -30,7 +31,8 @@ type rpcChat struct {
etcdAddr []string
messageWriter MessageWriter
//offlineProducer *kafka.Producer
delMsgCh chan deleteMsg
delMsgCh chan deleteMsg
dMessageLocker MessageLocker
}
type deleteMsg struct {
@ -47,6 +49,7 @@ func NewRpcChatServer(port int) *rpcChat {
rpcRegisterName: config.Config.RpcRegisterName.OpenImMsgName,
etcdSchema: config.Config.Etcd.EtcdSchema,
etcdAddr: config.Config.Etcd.EtcdAddr,
dMessageLocker: NewLockerMessage(),
}
rc.messageWriter = kafka.NewKafkaProducer(config.Config.Kafka.Ws2mschat.Addr, config.Config.Kafka.Ws2mschat.Topic)
//rc.offlineProducer = kafka.NewKafkaProducer(config.Config.Kafka.Ws2mschatOffline.Addr, config.Config.Kafka.Ws2mschatOffline.Topic)
@ -94,8 +97,12 @@ func (rpc *rpcChat) Run() {
panic("listening err:" + err.Error() + rpc.rpcRegisterName)
}
log.Info("", "listen network success, address ", address)
var grpcOpts []grpc.ServerOption
recvSize := 1024 * 1024 * 30
sendSize := 1024 * 1024 * 30
var grpcOpts = []grpc.ServerOption{
grpc.MaxRecvMsgSize(recvSize),
grpc.MaxSendMsgSize(sendSize),
}
if config.Config.Prometheus.Enable {
promePkg.NewGrpcRequestCounter()
promePkg.NewGrpcRequestFailedCounter()

View File

@ -25,6 +25,7 @@ import (
"time"
promePkg "Open_IM/pkg/common/prometheus"
go_redis "github.com/go-redis/redis/v8"
"github.com/golang/protobuf/proto"
)
@ -96,12 +97,24 @@ func isMessageHasReadEnabled(pb *pbChat.SendMsgReq) (bool, int32, string) {
return true, 0, ""
}
func userIsMuteInGroup(groupID, userID string) (bool, error) {
func userIsMuteAndIsAdminInGroup(groupID, userID string) (isMute bool, isAdmin bool, err error) {
groupMemberInfo, err := rocksCache.GetGroupMemberInfoFromCache(groupID, userID)
if err != nil {
return false, utils.Wrap(err, "")
return false, false, utils.Wrap(err, "")
}
if groupMemberInfo.MuteEndTime.Unix() >= time.Now().Unix() {
return true, groupMemberInfo.RoleLevel > constant.GroupOrdinaryUsers, nil
}
return false, groupMemberInfo.RoleLevel > constant.GroupOrdinaryUsers, nil
}
func groupIsMuted(groupID string) (bool, error) {
groupInfo, err := rocksCache.GetGroupInfoFromCache(groupID)
if err != nil {
return false, utils.Wrap(err, "GetGroupInfoFromCache failed")
}
if groupInfo.Status == constant.GroupStatusMuted {
return true, nil
}
return false, nil
@ -113,7 +126,7 @@ func (rpc *rpcChat) messageVerification(data *pbChat.SendMsgReq) (bool, int32, s
if utils.IsContain(data.MsgData.SendID, config.Config.Manager.AppManagerUid) {
return true, 0, "", nil
}
if data.MsgData.ContentType <= constant.NotificationEnd && data.MsgData.ContentType >= constant.NotificationBegin {
if data.MsgData.ContentType <= constant.NotificationEnd && data.MsgData.ContentType >= constant.NotificationBegin && data.MsgData.ContentType != constant.SignalingNotification {
return true, 0, "", nil
}
log.NewDebug(data.OperationID, *config.Config.MessageVerify.FriendVerify)
@ -171,16 +184,18 @@ func (rpc *rpcChat) messageVerification(data *pbChat.SendMsgReq) (bool, int32, s
log.NewError(data.OperationID, errMsg)
return false, 201, errMsg, nil
}
if !token_verify.IsManagerUserID(data.MsgData.SendID) {
if data.MsgData.ContentType <= constant.NotificationEnd && data.MsgData.ContentType >= constant.NotificationBegin {
return true, 0, "", userIDList
}
if token_verify.IsManagerUserID(data.MsgData.SendID) {
return true, 0, "", userIDList
}
if data.MsgData.ContentType <= constant.NotificationEnd && data.MsgData.ContentType >= constant.NotificationBegin {
return true, 0, "", userIDList
} else {
if !utils.IsContain(data.MsgData.SendID, userIDList) {
//return returnMsg(&replay, pb, 202, "you are not in group", "", 0)
return false, 202, "you are not in group", nil
}
}
isMute, err := userIsMuteInGroup(data.MsgData.GroupID, data.MsgData.SendID)
isMute, isAdmin, err := userIsMuteAndIsAdminInGroup(data.MsgData.GroupID, data.MsgData.SendID)
if err != nil {
errMsg := data.OperationID + err.Error()
return false, 223, errMsg, nil
@ -188,6 +203,17 @@ func (rpc *rpcChat) messageVerification(data *pbChat.SendMsgReq) (bool, int32, s
if isMute {
return false, 224, "you are muted", nil
}
if isAdmin {
return true, 0, "", userIDList
}
isMute, err = groupIsMuted(data.MsgData.GroupID)
if err != nil {
errMsg := data.OperationID + err.Error()
return false, 223, errMsg, nil
}
if isMute {
return false, 225, "group id muted", nil
}
return true, 0, "", userIDList
case constant.SuperGroupChatType:
groupInfo, err := rocksCache.GetGroupInfoFromCache(data.MsgData.GroupID)
@ -232,16 +258,18 @@ func (rpc *rpcChat) messageVerification(data *pbChat.SendMsgReq) (bool, int32, s
log.NewError(data.OperationID, errMsg)
return false, 201, errMsg, nil
}
if !token_verify.IsManagerUserID(data.MsgData.SendID) {
if data.MsgData.ContentType <= constant.NotificationEnd && data.MsgData.ContentType >= constant.NotificationBegin {
return true, 0, "", userIDList
}
if token_verify.IsManagerUserID(data.MsgData.SendID) {
return true, 0, "", userIDList
}
if data.MsgData.ContentType <= constant.NotificationEnd && data.MsgData.ContentType >= constant.NotificationBegin {
return true, 0, "", userIDList
} else {
if !utils.IsContain(data.MsgData.SendID, userIDList) {
//return returnMsg(&replay, pb, 202, "you are not in group", "", 0)
return false, 202, "you are not in group", nil
}
}
isMute, err := userIsMuteInGroup(data.MsgData.GroupID, data.MsgData.SendID)
isMute, isAdmin, err := userIsMuteAndIsAdminInGroup(data.MsgData.GroupID, data.MsgData.SendID)
if err != nil {
errMsg := data.OperationID + err.Error()
return false, 223, errMsg, nil
@ -249,6 +277,17 @@ func (rpc *rpcChat) messageVerification(data *pbChat.SendMsgReq) (bool, int32, s
if isMute {
return false, 224, "you are muted", nil
}
if isAdmin {
return true, 0, "", userIDList
}
isMute, err = groupIsMuted(data.MsgData.GroupID)
if err != nil {
errMsg := data.OperationID + err.Error()
return false, 223, errMsg, nil
}
if isMute {
return false, 225, "group id muted", nil
}
return true, 0, "", userIDList
}
default:
@ -962,6 +1001,13 @@ func Notification(n *NotificationMsg) {
ex = config.Config.Notification.ConversationSetPrivate.OfflinePush.Ext
reliabilityLevel = config.Config.Notification.ConversationSetPrivate.Conversation.ReliabilityLevel
unReadCount = config.Config.Notification.ConversationSetPrivate.Conversation.UnreadCount
case constant.FriendInfoUpdatedNotification:
pushSwitch = config.Config.Notification.FriendInfoUpdated.OfflinePush.PushSwitch
title = config.Config.Notification.FriendInfoUpdated.OfflinePush.Title
desc = config.Config.Notification.FriendInfoUpdated.OfflinePush.Desc
ex = config.Config.Notification.FriendInfoUpdated.OfflinePush.Ext
reliabilityLevel = config.Config.Notification.FriendInfoUpdated.Conversation.ReliabilityLevel
unReadCount = config.Config.Notification.FriendInfoUpdated.Conversation.UnreadCount
case constant.DeleteMessageNotification:
reliabilityLevel = constant.ReliableNotificationNoMsg
case constant.ConversationUnreadNotification, constant.SuperGroupUpdateNotification:

View File

@ -10,15 +10,6 @@ import (
)
func SuperGroupNotification(operationID, sendID, recvID string) {
//var tips sdk.TipsComm
//var err error
//marshaler := jsonpb.Marshaler{
// OrigName: true,
// EnumsAsInts: false,
// EmitDefaults: false,
//}
//tips.JsonDetail, _ = marshaler.MarshalToString(m)
n := &NotificationMsg{
SendID: sendID,
RecvID: recvID,
@ -27,11 +18,6 @@ func SuperGroupNotification(operationID, sendID, recvID string) {
SessionType: constant.SingleChatType,
OperationID: operationID,
}
//n.Content, err = proto.Marshal(&tips)
//if err != nil {
// log.NewError(operationID, utils.GetSelfFuncName(), "proto.Marshal failed")
// return
//}
log.NewInfo(operationID, utils.GetSelfFuncName(), string(n.Content))
Notification(n)
}

View File

@ -444,13 +444,15 @@ func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbUser.UpdateUserI
}
for _, v := range rpcResp.FriendInfoList {
log.Info(req.OperationID, "UserInfoUpdatedNotification ", req.UserInfo.UserID, v.FriendUser.UserID)
chat.UserInfoUpdatedNotification(req.OperationID, req.UserInfo.UserID, v.FriendUser.UserID)
// chat.UserInfoUpdatedNotification(req.OperationID, req.UserInfo.UserID, v.FriendUser.UserID)
chat.FriendInfoUpdatedNotification(req.OperationID, req.UserInfo.UserID, v.FriendUser.UserID, req.OpUserID)
}
if err := rocksCache.DelUserInfoFromCache(user.UserID); err != nil {
log.NewError(req.OperationID, "GetFriendList failed ", err.Error(), newReq)
return &pbUser.UpdateUserInfoResp{CommonResp: &pbUser.CommonResp{ErrCode: constant.ErrDB.ErrCode, ErrMsg: err.Error()}}, nil
}
chat.UserInfoUpdatedNotification(req.OperationID, req.UserInfo.UserID, req.OpUserID)
//chat.UserInfoUpdatedNotification(req.OperationID, req.OpUserID, req.UserInfo.UserID)
chat.UserInfoUpdatedNotification(req.OperationID, req.OpUserID, req.UserInfo.UserID)
log.Info(req.OperationID, "UserInfoUpdatedNotification ", req.UserInfo.UserID, req.OpUserID)
if req.UserInfo.FaceURL != "" {
s.SyncJoinedGroupMemberFaceURL(req.UserInfo.UserID, req.UserInfo.FaceURL, req.OperationID, req.OpUserID)

View File

@ -1,5 +1,10 @@
package base_info
import (
"Open_IM/pkg/proto/msg"
sdk_ws "Open_IM/pkg/proto/sdk_ws"
)
type DelMsgReq struct {
UserID string `json:"userID,omitempty" binding:"required"`
SeqList []uint32 `json:"seqList,omitempty" binding:"required"`
@ -18,6 +23,7 @@ type CleanUpMsgReq struct {
type CleanUpMsgResp struct {
CommResp
}
type DelSuperGroupMsgReq struct {
UserID string `json:"userID" binding:"required"`
GroupID string `json:"groupID" binding:"required"`
@ -29,23 +35,108 @@ type DelSuperGroupMsgReq struct {
type DelSuperGroupMsgResp struct {
CommResp
}
type MsgDeleteNotificationElem struct {
GroupID string `json:"groupID"`
IsAllDelete bool `json:"isAllDelete"`
SeqList []uint32 `json:"seqList"`
}
//UserID string `protobuf:"bytes,1,opt,name=userID" json:"userID,omitempty"`
// GroupID string `protobuf:"bytes,2,opt,name=groupID" json:"groupID,omitempty"`
// MinSeq uint32 `protobuf:"varint,3,opt,name=minSeq" json:"minSeq,omitempty"`
// OperationID string `protobuf:"bytes,4,opt,name=operationID" json:"operationID,omitempty"`
// OpUserID string `protobuf:"bytes,5,opt,name=opUserID" json:"opUserID,omitempty"`
type SetMsgMinSeqReq struct {
UserID string `json:"userID" binding:"required"`
GroupID string `json:"groupID"`
MinSeq uint32 `json:"minSeq" binding:"required"`
OperationID string `json:"operationID" binding:"required"`
}
type SetMsgMinSeqResp struct {
CommResp
}
type ModifyMessageReactionExtensionsReq struct {
OperationID string `json:"operationID" binding:"required"`
SourceID string `json:"sourceID" binding:"required"`
SessionType int32 `json:"sessionType" binding:"required"`
ReactionExtensionList map[string]*sdk_ws.KeyValue `json:"reactionExtensionList,omitempty" binding:"required"`
ClientMsgID string `json:"clientMsgID" binding:"required"`
Ex *string `json:"ex"`
AttachedInfo *string `json:"attachedInfo"`
IsReact bool `json:"isReact"`
IsExternalExtensions bool `json:"isExternalExtensions"`
MsgFirstModifyTime int64 `json:"msgFirstModifyTime"`
}
type ModifyMessageReactionExtensionsResp struct {
CommResp
Data struct {
ResultKeyValue []*msg.KeyValueResp `json:"result"`
MsgFirstModifyTime int64 `json:"msgFirstModifyTime"`
IsReact bool `json:"isReact"`
} `json:"data"`
}
type OperateMessageListReactionExtensionsReq struct {
OperationID string `json:"operationID" binding:"required"`
SourceID string `json:"sourceID" binding:"required"`
SessionType string `json:"sessionType" binding:"required"`
IsExternalExtensions bool `json:"isExternalExtensions"`
MessageReactionKeyList []*msg.GetMessageListReactionExtensionsReq_MessageReactionKey `json:"messageReactionKeyList" binding:"required"`
}
type OperateMessageListReactionExtensionsResp struct {
CommResp
Data struct {
SuccessList []*msg.ExtendMsgResp `json:"successList"`
FailedList []*msg.ExtendMsgResp `json:"failedList"`
} `json:"data"`
}
type SetMessageReactionExtensionsCallbackReq ModifyMessageReactionExtensionsReq
type SetMessageReactionExtensionsCallbackResp ModifyMessageReactionExtensionsResp
type GetMessageListReactionExtensionsReq OperateMessageListReactionExtensionsReq
type GetMessageListReactionExtensionsResp struct {
CommResp
Data []*msg.SingleMessageExtensionResult `json:"data"`
}
type AddMessageReactionExtensionsReq ModifyMessageReactionExtensionsReq
type AddMessageReactionExtensionsResp ModifyMessageReactionExtensionsResp
type DeleteMessageReactionExtensionsReq struct {
OperationID string `json:"operationID" binding:"required"`
SourceID string `json:"sourceID" binding:"required"`
SessionType int32 `json:"sessionType" binding:"required"`
ClientMsgID string `json:"clientMsgID" binding:"required"`
IsExternalExtensions bool `json:"isExternalExtensions"`
MsgFirstModifyTime int64 `json:"msgFirstModifyTime" binding:"required"`
ReactionExtensionList []*sdk_ws.KeyValue `json:"reactionExtensionList" binding:"required"`
}
type DeleteMessageReactionExtensionsResp struct {
CommResp
Data []*msg.KeyValueResp
}
type ReactionMessageModifierNotification struct {
SourceID string `json:"sourceID" binding:"required"`
OpUserID string `json:"opUserID" binding:"required"`
SessionType int32 `json:"sessionType" binding:"required"`
SuccessReactionExtensionList map[string]*sdk_ws.KeyValue `json:"reactionExtensionList,omitempty" binding:"required"`
ClientMsgID string `json:"clientMsgID" binding:"required"`
IsReact bool `json:"isReact"`
IsExternalExtensions bool `json:"isExternalExtensions"`
MsgFirstModifyTime int64 `json:"msgFirstModifyTime"`
}
type ReactionMessageDeleteNotification struct {
SourceID string `json:"sourceID" binding:"required"`
OpUserID string `json:"opUserID" binding:"required"`
SessionType int32 `json:"sessionType" binding:"required"`
SuccessReactionExtensionList map[string]*sdk_ws.KeyValue `json:"reactionExtensionList,omitempty" binding:"required"`
ClientMsgID string `json:"clientMsgID" binding:"required"`
MsgFirstModifyTime int64 `json:"msgFirstModifyTime"`
}

View File

@ -1,12 +1,15 @@
package call_back_struct
import (
"Open_IM/pkg/proto/group"
commonPb "Open_IM/pkg/proto/sdk_ws"
)
type CallbackBeforeCreateGroupReq struct {
CallbackCommand string `json:"callbackCommand"`
OperationID string `json:"operationID"`
commonPb.GroupInfo
InitMemberList []*group.GroupAddMemberInfo `json:"initMemberList"`
}
type CallbackBeforeCreateGroupResp struct {
@ -25,3 +28,40 @@ type CallbackBeforeCreateGroupResp struct {
LookMemberInfo *int32 `json:"lookMemberInfo"`
ApplyMemberFriend *int32 `json:"applyMemberFriend"`
}
type CallbackBeforeMemberJoinGroupReq struct {
CallbackCommand string `json:"callbackCommand"`
OperationID string `json:"operationID"`
GroupID string `json:"groupID"`
UserID string `json:"userID"`
Ex string `json:"ex"`
GroupEx string `json:"groupEx"`
}
type CallbackBeforeMemberJoinGroupResp struct {
*CommonCallbackResp
NickName *string `json:"nickName"`
FaceURL *string `json:"faceURL"`
RoleLevel *int32 `json:"roleLevel"`
MuteEndTime *int64 `json:"muteEndTime"`
Ex *string `json:"ex"`
}
type CallbackBeforeSetGroupMemberInfoReq struct {
CallbackCommand string `json:"callbackCommand"`
OperationID string `json:"operationID"`
GroupID string `json:"groupID"`
UserID string `json:"userID"`
Nickname string `json:"nickName"`
FaceURL string `json:"faceURL"`
RoleLevel int32 `json:"roleLevel"`
Ex string `json:"ex"`
}
type CallbackBeforeSetGroupMemberInfoResp struct {
*CommonCallbackResp
Ex *string `json:"ex"`
Nickname *string `json:"nickName"`
FaceURL *string `json:"faceURL"`
RoleLevel *int32 `json:"roleLevel"`
}

View File

@ -1,6 +1,9 @@
package call_back_struct
import sdk_ws "Open_IM/pkg/proto/sdk_ws"
import (
"Open_IM/pkg/proto/msg"
sdk_ws "Open_IM/pkg/proto/sdk_ws"
)
type CallbackBeforeSendSingleMsgReq struct {
CommonCallbackReq
@ -63,3 +66,48 @@ type CallbackMsgModifyCommandResp struct {
AttachedInfo *string `json:"attachedInfo"`
Ex *string `json:"ex"`
}
type CallbackBeforeSetMessageReactionExtReq struct {
OperationID string `json:"operationID"`
CallbackCommand string `json:"callbackCommand"`
SourceID string `json:"sourceID"`
OpUserID string `json:"opUserID"`
SessionType int32 `json:"sessionType"`
ReactionExtensionList map[string]*sdk_ws.KeyValue `json:"reactionExtensionList"`
ClientMsgID string `json:"clientMsgID"`
IsReact bool `json:"isReact"`
IsExternalExtensions bool `json:"isExternalExtensions"`
MsgFirstModifyTime int64 `json:"msgFirstModifyTime"`
}
type CallbackBeforeSetMessageReactionExtResp struct {
*CommonCallbackResp
ResultReactionExtensionList []*msg.KeyValueResp `json:"resultReactionExtensionList"`
MsgFirstModifyTime int64 `json:"msgFirstModifyTime"`
}
type CallbackDeleteMessageReactionExtReq struct {
OperationID string `json:"operationID"`
CallbackCommand string `json:"callbackCommand"`
SourceID string `json:"sourceID"`
OpUserID string `json:"opUserID"`
SessionType int32 `json:"sessionType"`
ReactionExtensionList []*sdk_ws.KeyValue `json:"reactionExtensionList"`
ClientMsgID string `json:"clientMsgID"`
IsExternalExtensions bool `json:"isExternalExtensions"`
MsgFirstModifyTime int64 `json:"msgFirstModifyTime"`
}
type CallbackDeleteMessageReactionExtResp struct {
*CommonCallbackResp
ResultReactionExtensionList []*msg.KeyValueResp `json:"resultReactionExtensionList"`
MsgFirstModifyTime int64 `json:"msgFirstModifyTime"`
}
type CallbackGetMessageListReactionExtReq struct {
OperationID string `json:"operationID"`
CallbackCommand string `json:"callbackCommand"`
SourceID string `json:"sourceID"`
OpUserID string `json:"opUserID"`
SessionType int32 `json:"sessionType"`
MessageKeyList []*msg.GetMessageListReactionExtensionsReq_MessageReactionKey `json:"messageKeyList"`
}
type CallbackGetMessageListReactionExtResp struct {
*CommonCallbackResp
MessageResultList []*msg.SingleMessageExtensionResult `json:"messageResultList"`
}

View File

@ -2,8 +2,10 @@ package call_back_struct
type CallbackUserOnlineReq struct {
UserStatusCallbackReq
Token string `json:"token"`
Seq int `json:"seq"`
Token string `json:"token"`
Seq int `json:"seq"`
IsAppBackground bool `json:"isAppBackground"`
ConnID string `json:"connID"`
}
type CallbackUserOnlineResp struct {
@ -12,7 +14,8 @@ type CallbackUserOnlineResp struct {
type CallbackUserOfflineReq struct {
UserStatusCallbackReq
Seq int `json:"seq"`
Seq int `json:"seq"`
ConnID string `json:"connID"`
}
type CallbackUserOfflineResp struct {

View File

@ -21,7 +21,7 @@ type CallbackBeforePushResp struct {
}
type CallbackBeforeSuperGroupOnlinePushReq struct {
*commonPb.OfflinePushInfo
//*commonPb.OfflinePushInfo
UserStatusBaseCallback
ClientMsgID string `json:"clientMsgID"`
SendID string `json:"sendID"`
@ -30,6 +30,7 @@ type CallbackBeforeSuperGroupOnlinePushReq struct {
SessionType int32 `json:"sessionType"`
AtUserIDList []string `json:"atUserIDList"`
Content string `json:"content"`
Seq uint32 `json:"seq"`
}
type CallbackBeforeSuperGroupOnlinePushResp struct {

View File

@ -17,6 +17,17 @@ type AdminLoginResponse struct {
FaceURL string `json:"faceURL"`
}
type GetUserTokenRequest struct {
UserID string `json:"userID" binding:"required"`
OperationID string `json:"operationID" binding:"required"`
PlatFormID int32 `json:"platformID" binding:"required"`
}
type GetUserTokenResponse struct {
Token string `json:"token"`
ExpTime int64 `json:"expTime"`
}
type AddUserRegisterAddFriendIDListRequest struct {
OperationID string `json:"operationID" binding:"required"`
UserIDList []string `json:"userIDList" binding:"required"`

View File

@ -248,11 +248,16 @@ type config struct {
Addr []string `yaml:"addr"`
Topic string `yaml:"topic"`
}
MsgToModify struct {
Addr []string `yaml:"addr"`
Topic string `yaml:"topic"`
}
ConsumerGroupID struct {
MsgToRedis string `yaml:"msgToTransfer"`
MsgToMongo string `yaml:"msgToMongo"`
MsgToMySql string `yaml:"msgToMySql"`
MsgToPush string `yaml:"msgToPush"`
MsgToRedis string `yaml:"msgToTransfer"`
MsgToMongo string `yaml:"msgToMongo"`
MsgToMySql string `yaml:"msgToMySql"`
MsgToPush string `yaml:"msgToPush"`
MsgToModify string `yaml:"msgToModify"`
}
}
Secret string `yaml:"secret"`
@ -291,6 +296,8 @@ type config struct {
CallbackBeforeSuperGroupOnlinePush callBackConfig `yaml:"callbackSuperGroupOnlinePush"`
CallbackBeforeAddFriend callBackConfig `yaml:"callbackBeforeAddFriend"`
CallbackBeforeCreateGroup callBackConfig `yaml:"callbackBeforeCreateGroup"`
CallbackBeforeMemberJoinGroup callBackConfig `yaml:"callbackBeforeMemberJoinGroup"`
CallbackBeforeSetGroupMemberInfo callBackConfig `yaml:"callbackBeforeSetGroupMemberInfo"`
} `yaml:"callback"`
Notification struct {
///////////////////////group/////////////////////////////
@ -455,6 +462,12 @@ type config struct {
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"blackDeleted"`
FriendInfoUpdated struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
DefaultTips PDefaultTips `yaml:"defaultTips"`
} `yaml:"friendInfoUpdated"`
ConversationOptUpdate struct {
Conversation PConversation `yaml:"conversation"`
OfflinePush POfflinePush `yaml:"offlinePush"`
@ -640,7 +653,7 @@ func unmarshalConfig(config interface{}, configName string) {
} else {
bytes, err := ioutil.ReadFile(fmt.Sprintf("../config/%s", configName))
if err != nil {
panic(err.Error())
panic(err.Error() + configName)
}
if err = yaml.Unmarshal(bytes, config); err != nil {
panic(err.Error())

View File

@ -17,14 +17,15 @@ const (
RefuseFriendFlag = -1
//Websocket Protocol
WSGetNewestSeq = 1001
WSPullMsgBySeqList = 1002
WSSendMsg = 1003
WSSendSignalMsg = 1004
WSPushMsg = 2001
WSKickOnlineMsg = 2002
WsLogoutMsg = 2003
WSDataError = 3001
WSGetNewestSeq = 1001
WSPullMsgBySeqList = 1002
WSSendMsg = 1003
WSSendSignalMsg = 1004
WSPushMsg = 2001
WSKickOnlineMsg = 2002
WsLogoutMsg = 2003
WsSetBackgroundStatus = 2004
WSDataError = 3001
///ContentType
//UserRelated
@ -47,6 +48,8 @@ const (
AdvancedRevoke = 118 //影响前者消息
CustomNotTriggerConversation = 119
CustomOnlineOnly = 120
ReactionMessageModifier = 121
ReactionMessageDeleter = 122
Common = 200
GroupMsg = 201
@ -64,11 +67,12 @@ const (
FriendRemarkSetNotification = 1206 //set_friend_remark?
BlackAddedNotification = 1207 //add_black
BlackDeletedNotification = 1208 //remove_black
FriendInfoUpdatedNotification = 1209
ConversationOptChangeNotification = 1300 // change conversation opt
UserNotificationBegin = 1301
UserInfoUpdatedNotification = 1303 //SetSelfInfoTip = 204
UserInfoUpdatedNotification = 1303 //SetSelfInfoTip = 204
UserNotificationEnd = 1399
OANotification = 1400
@ -110,6 +114,10 @@ const (
WorkMomentNotificationBegin = 1900
WorkMomentNotification = 1901
BusinessNotificationBegin = 2000
BusinessNotification = 2001
BusinessNotificationEnd = 2099
NotificationEnd = 3000
//status
@ -163,6 +171,7 @@ const (
IsNotPrivate = "notPrivate"
IsSenderConversationUpdate = "senderConversationUpdate"
IsSenderNotificationPush = "senderNotificationPush"
IsReactionFromCache = "reactionFromCache"
//GroupStatus
GroupOk = 0
@ -196,19 +205,24 @@ const (
VerificationCodeForResetSuffix = "_forReset"
//callbackCommand
CallbackBeforeSendSingleMsgCommand = "callbackBeforeSendSingleMsgCommand"
CallbackAfterSendSingleMsgCommand = "callbackAfterSendSingleMsgCommand"
CallbackBeforeSendGroupMsgCommand = "callbackBeforeSendGroupMsgCommand"
CallbackAfterSendGroupMsgCommand = "callbackAfterSendGroupMsgCommand"
CallbackMsgModifyCommand = "callbackMsgModifyCommand"
CallbackUserOnlineCommand = "callbackUserOnlineCommand"
CallbackUserOfflineCommand = "callbackUserOfflineCommand"
CallbackUserKickOffCommand = "callbackUserKickOffCommand"
CallbackOfflinePushCommand = "callbackOfflinePushCommand"
CallbackOnlinePushCommand = "callbackOnlinePushCommand"
CallbackSuperGroupOnlinePushCommand = "callbackSuperGroupOnlinePushCommand"
CallbackBeforeAddFriendCommand = "callbackBeforeAddFriendCommand"
CallbackBeforeCreateGroupCommand = "callbackBeforeCreateGroup"
CallbackBeforeSendSingleMsgCommand = "callbackBeforeSendSingleMsgCommand"
CallbackAfterSendSingleMsgCommand = "callbackAfterSendSingleMsgCommand"
CallbackBeforeSendGroupMsgCommand = "callbackBeforeSendGroupMsgCommand"
CallbackAfterSendGroupMsgCommand = "callbackAfterSendGroupMsgCommand"
CallbackMsgModifyCommand = "callbackMsgModifyCommand"
CallbackUserOnlineCommand = "callbackUserOnlineCommand"
CallbackUserOfflineCommand = "callbackUserOfflineCommand"
CallbackUserKickOffCommand = "callbackUserKickOffCommand"
CallbackOfflinePushCommand = "callbackOfflinePushCommand"
CallbackOnlinePushCommand = "callbackOnlinePushCommand"
CallbackSuperGroupOnlinePushCommand = "callbackSuperGroupOnlinePushCommand"
CallbackBeforeAddFriendCommand = "callbackBeforeAddFriendCommand"
CallbackBeforeCreateGroupCommand = "callbackBeforeCreateGroupCommand"
CallbackBeforeMemberJoinGroupCommand = "callbackBeforeMemberJoinGroupCommand"
CallbackBeforeSetGroupMemberInfoCommand = "CallbackBeforeSetGroupMemberInfoCommand"
CallbackBeforeSetMessageReactionExtensionCommand = "callbackBeforeSetMessageReactionExtensionCommand"
CallbackBeforeDeleteMessageReactionExtensionsCommand = "callbackBeforeDeleteMessageReactionExtensionsCommand"
CallbackGetMessageListReactionExtensionsCommand = "callbackGetMessageListReactionExtensionsCommand"
//callback actionCode
ActionAllow = 0
@ -339,6 +353,6 @@ const LogFileName = "OpenIM.log"
const StatisticsTimeInterval = 60
const MaxNotificationNum = 100
const MaxNotificationNum = 500
const CurrentVersion = "v2.3.4-rc0"

View File

@ -33,6 +33,7 @@ var (
ErrSendLimit = ErrInfo{ErrCode: 810, ErrMsg: "send msg limit, to many request, try again later"}
ErrMessageHasReadDisable = ErrInfo{ErrCode: 811, ErrMsg: "message has read disable"}
ErrInternal = ErrInfo{ErrCode: 812, ErrMsg: "internal error"}
ErrWsConnNotExist = ErrInfo{ErrCode: 813, ErrMsg: "ws conn not exist"}
)
var (

View File

@ -14,6 +14,7 @@ const (
LinuxPlatformID = 7
AndroidPadPlatformID = 8
IPadPlatformID = 9
AdminPlatformID = 10
//Platform string match to Platform ID
IOSPlatformStr = "IOS"
@ -25,6 +26,7 @@ const (
LinuxPlatformStr = "Linux"
AndroidPadPlatformStr = "APad"
IPadPlatformStr = "IPad"
AdminPlatformStr = "Admin"
//terminal types
TerminalPC = "PC"
@ -41,6 +43,7 @@ var PlatformID2Name = map[int]string{
LinuxPlatformID: LinuxPlatformStr,
AndroidPadPlatformID: AndroidPadPlatformStr,
IPadPlatformID: IPadPlatformStr,
AdminPlatformID: AdminPlatformStr,
}
var PlatformName2ID = map[string]int{
IOSPlatformStr: IOSPlatformID,
@ -52,8 +55,9 @@ var PlatformName2ID = map[string]int{
LinuxPlatformStr: LinuxPlatformID,
AndroidPadPlatformStr: AndroidPadPlatformID,
IPadPlatformStr: IPadPlatformID,
AdminPlatformStr: AdminPlatformID,
}
var Platform2class = map[string]string{
var PlatformName2class = map[string]string{
IOSPlatformStr: TerminalMobile,
AndroidPlatformStr: TerminalMobile,
MiniWebPlatformStr: WebPlatformStr,
@ -62,6 +66,15 @@ var Platform2class = map[string]string{
OSXPlatformStr: TerminalPC,
LinuxPlatformStr: TerminalPC,
}
var PlatformID2class = map[int]string{
IOSPlatformID: TerminalMobile,
AndroidPlatformID: TerminalMobile,
MiniWebPlatformID: WebPlatformStr,
WebPlatformID: WebPlatformStr,
WindowsPlatformID: TerminalPC,
OSXPlatformID: TerminalPC,
LinuxPlatformID: TerminalPC,
}
func PlatformIDToName(num int) string {
return PlatformID2Name[num]
@ -70,5 +83,8 @@ func PlatformNameToID(name string) int {
return PlatformName2ID[name]
}
func PlatformNameToClass(name string) string {
return Platform2class[name]
return PlatformName2class[name]
}
func PlatformIDToClass(num int) string {
return PlatformID2class[num]
}

View File

@ -28,6 +28,7 @@ const (
uidPidToken = "UID_PID_TOKEN_STATUS:"
conversationReceiveMessageOpt = "CON_RECV_MSG_OPT:"
getuiToken = "GETUI_TOKEN"
getuiTaskID = "GETUI_TASK_ID"
messageCache = "MESSAGE_CACHE:"
SignalCache = "SIGNAL_CACHE:"
SignalListCache = "SIGNAL_LIST_CACHE:"
@ -38,6 +39,7 @@ const (
groupMinSeq = "GROUP_MIN_SEQ:"
sendMsgFailedFlag = "SEND_MSG_FAILED_FLAG:"
userBadgeUnreadCountSum = "USER_BADGE_UNREAD_COUNT_SUM:"
exTypeKeyLocker = "EX_LOCK:"
)
func (d *DataBases) JudgeAccountEXISTS(account string) (bool, error) {
@ -397,6 +399,15 @@ func (d *DataBases) GetGetuiToken() (string, error) {
return result, err
}
func (d *DataBases) SetGetuiTaskID(taskID string, expireTime int64) error {
return d.RDB.Set(context.Background(), getuiTaskID, taskID, time.Duration(expireTime)*time.Second).Err()
}
func (d *DataBases) GetGetuiTaskID() (string, error) {
result, err := d.RDB.Get(context.Background(), getuiTaskID).Result()
return result, err
}
func (d *DataBases) SetSendMsgStatus(status int32, operationID string) error {
return d.RDB.Set(context.Background(), sendMsgFailedFlag+operationID, status, time.Hour*24).Err()
}
@ -437,3 +448,61 @@ func (d *DataBases) GetUserBadgeUnreadCountSum(uid string) (int, error) {
seq, err := d.RDB.Get(context.Background(), key).Result()
return utils.StringToInt(seq), err
}
func (d *DataBases) JudgeMessageReactionEXISTS(clientMsgID string, sessionType int32) (bool, error) {
key := getMessageReactionExPrefix(clientMsgID, sessionType)
n, err := d.RDB.Exists(context.Background(), key).Result()
if n > 0 {
return true, err
} else {
return false, err
}
}
func (d *DataBases) GetOneMessageAllReactionList(clientMsgID string, sessionType int32) (map[string]string, error) {
key := getMessageReactionExPrefix(clientMsgID, sessionType)
return d.RDB.HGetAll(context.Background(), key).Result()
}
func (d *DataBases) DeleteOneMessageKey(clientMsgID string, sessionType int32, subKey string) error {
key := getMessageReactionExPrefix(clientMsgID, sessionType)
return d.RDB.HDel(context.Background(), key, subKey).Err()
}
func (d *DataBases) SetMessageReactionExpire(clientMsgID string, sessionType int32, expiration time.Duration) (bool, error) {
key := getMessageReactionExPrefix(clientMsgID, sessionType)
return d.RDB.Expire(context.Background(), key, expiration).Result()
}
func (d *DataBases) GetMessageTypeKeyValue(clientMsgID string, sessionType int32, typeKey string) (string, error) {
key := getMessageReactionExPrefix(clientMsgID, sessionType)
result, err := d.RDB.HGet(context.Background(), key, typeKey).Result()
return result, err
}
func (d *DataBases) SetMessageTypeKeyValue(clientMsgID string, sessionType int32, typeKey, value string) error {
key := getMessageReactionExPrefix(clientMsgID, sessionType)
return d.RDB.HSet(context.Background(), key, typeKey, value).Err()
}
func (d *DataBases) LockMessageTypeKey(clientMsgID string, TypeKey string) error {
key := exTypeKeyLocker + clientMsgID + "_" + TypeKey
return d.RDB.SetNX(context.Background(), key, 1, time.Minute).Err()
}
func (d *DataBases) UnLockMessageTypeKey(clientMsgID string, TypeKey string) error {
key := exTypeKeyLocker + clientMsgID + "_" + TypeKey
return d.RDB.Del(context.Background(), key).Err()
}
func getMessageReactionExPrefix(clientMsgID string, sessionType int32) string {
switch sessionType {
case constant.SingleChatType:
return "EX_SINGLE_" + clientMsgID
case constant.GroupChatType:
return "EX_GROUP_" + clientMsgID
case constant.SuperGroupChatType:
return "EX_SUPER_GROUP_" + clientMsgID
case constant.NotificationChatType:
return "EX_NOTIFICATION" + clientMsgID
}
return ""
}

View File

@ -0,0 +1,205 @@
package db
import (
"Open_IM/pkg/common/config"
server_api_params "Open_IM/pkg/proto/sdk_ws"
"Open_IM/pkg/utils"
"context"
"errors"
"fmt"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"strconv"
"strings"
"time"
"go.mongodb.org/mongo-driver/bson"
)
const cExtendMsgSet = "extend_msgs"
const MaxNum = 100
type ExtendMsgSet struct {
SourceID string `bson:"source_id" json:"sourceID"`
SessionType int32 `bson:"session_type" json:"sessionType"`
ExtendMsgs map[string]ExtendMsg `bson:"extend_msgs" json:"extendMsgs"`
ExtendMsgNum int32 `bson:"extend_msg_num" json:"extendMsgNum"`
CreateTime int64 `bson:"create_time" json:"createTime"` // this block's create time
MaxMsgUpdateTime int64 `bson:"max_msg_update_time" json:"maxMsgUpdateTime"` // index find msg
}
type KeyValue struct {
TypeKey string `bson:"type_key" json:"typeKey"`
Value string `bson:"value" json:"value"`
LatestUpdateTime int64 `bson:"latest_update_time" json:"latestUpdateTime"`
}
type ExtendMsg struct {
ReactionExtensionList map[string]KeyValue `bson:"reaction_extension_list" json:"reactionExtensionList"`
ClientMsgID string `bson:"client_msg_id" json:"clientMsgID"`
MsgFirstModifyTime int64 `bson:"msg_first_modify_time" json:"msgFirstModifyTime"` // this extendMsg create time
AttachedInfo string `bson:"attached_info" json:"attachedInfo"`
Ex string `bson:"ex" json:"ex"`
}
func GetExtendMsgMaxNum() int32 {
return MaxNum
}
func GetExtendMsgSourceID(ID string, index int32) string {
return ID + ":" + strconv.Itoa(int(index))
}
func SplitSourceIDAndGetIndex(sourceID string) int32 {
l := strings.Split(sourceID, ":")
index, _ := strconv.Atoi(l[len(l)-1])
return int32(index)
}
func (d *DataBases) CreateExtendMsgSet(set *ExtendMsgSet) error {
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cExtendMsgSet)
_, err := c.InsertOne(ctx, set)
return err
}
type GetAllExtendMsgSetOpts struct {
ExcludeExtendMsgs bool
}
func (d *DataBases) GetAllExtendMsgSet(ID string, opts *GetAllExtendMsgSetOpts) (sets []*ExtendMsgSet, err error) {
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cExtendMsgSet)
regex := fmt.Sprintf("^%s", ID)
var findOpts *options.FindOptions
if opts != nil {
if opts.ExcludeExtendMsgs {
findOpts = &options.FindOptions{}
findOpts.SetProjection(bson.M{"extend_msgs": 0})
}
}
cursor, err := c.Find(ctx, bson.M{"uid": primitive.Regex{Pattern: regex}}, findOpts)
if err != nil {
return nil, utils.Wrap(err, "")
}
err = cursor.All(context.Background(), &sets)
if err != nil {
return nil, utils.Wrap(err, fmt.Sprintf("cursor is %s", cursor.Current.String()))
}
return sets, nil
}
func (d *DataBases) GetExtendMsgSet(ctx context.Context, sourceID string, sessionType int32, maxMsgUpdateTime int64, c *mongo.Collection) (*ExtendMsgSet, error) {
regex := fmt.Sprintf("^%s", sourceID)
var err error
findOpts := options.Find().SetLimit(1).SetSkip(0).SetSort(bson.M{"source_id": -1}).SetProjection(bson.M{"extend_msgs": 0})
// update newest
find := bson.M{"source_id": primitive.Regex{Pattern: regex}, "session_type": sessionType}
if maxMsgUpdateTime > 0 {
find["max_msg_update_time"] = maxMsgUpdateTime
}
result, err := c.Find(ctx, find, findOpts)
if err != nil {
return nil, utils.Wrap(err, "")
}
var setList []ExtendMsgSet
if err := result.All(ctx, &setList); err != nil {
return nil, utils.Wrap(err, "")
}
if len(setList) == 0 {
return nil, nil
}
return &setList[0], nil
}
// first modify msg
func (d *DataBases) InsertExtendMsg(sourceID string, sessionType int32, msg *ExtendMsg) error {
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cExtendMsgSet)
set, err := d.GetExtendMsgSet(ctx, sourceID, sessionType, 0, c)
if err != nil {
return utils.Wrap(err, "")
}
if set == nil || set.ExtendMsgNum >= GetExtendMsgMaxNum() {
var index int32
if set != nil {
index = SplitSourceIDAndGetIndex(set.SourceID)
}
err = d.CreateExtendMsgSet(&ExtendMsgSet{
SourceID: GetExtendMsgSourceID(sourceID, index),
SessionType: sessionType,
ExtendMsgs: map[string]ExtendMsg{msg.ClientMsgID: *msg},
ExtendMsgNum: 1,
CreateTime: msg.MsgFirstModifyTime,
MaxMsgUpdateTime: msg.MsgFirstModifyTime,
})
} else {
_, err = c.UpdateOne(ctx, bson.M{"source_id": set.SourceID, "session_type": sessionType}, bson.M{"$set": bson.M{"max_msg_update_time": msg.MsgFirstModifyTime, "$inc": bson.M{"extend_msg_num": 1}, fmt.Sprintf("extend_msgs.%s", msg.ClientMsgID): msg}})
}
return utils.Wrap(err, "")
}
// insert or update
func (d *DataBases) InsertOrUpdateReactionExtendMsgSet(sourceID string, sessionType int32, clientMsgID string, msgFirstModifyTime int64, reactionExtensionList map[string]*server_api_params.KeyValue) error {
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cExtendMsgSet)
var updateBson = bson.M{}
for _, v := range reactionExtensionList {
updateBson[fmt.Sprintf("extend_msgs.%s.%s", clientMsgID, v.TypeKey)] = v
}
upsert := true
opt := &options.UpdateOptions{
Upsert: &upsert,
}
set, err := d.GetExtendMsgSet(ctx, sourceID, sessionType, msgFirstModifyTime, c)
if err != nil {
return utils.Wrap(err, "")
}
if set == nil {
return errors.New(fmt.Sprintf("sourceID %s has no set", sourceID))
}
_, err = c.UpdateOne(ctx, bson.M{"source_id": set.SourceID, "session_type": sessionType}, bson.M{"$set": updateBson}, opt)
return utils.Wrap(err, "")
}
// delete TypeKey
func (d *DataBases) DeleteReactionExtendMsgSet(sourceID string, sessionType int32, clientMsgID string, msgFirstModifyTime int64, reactionExtensionList map[string]*server_api_params.KeyValue) error {
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cExtendMsgSet)
var updateBson = bson.M{}
for _, v := range reactionExtensionList {
updateBson[fmt.Sprintf("extend_msgs.%s.%s", clientMsgID, v.TypeKey)] = ""
}
set, err := d.GetExtendMsgSet(ctx, sourceID, sessionType, msgFirstModifyTime, c)
if err != nil {
return utils.Wrap(err, "")
}
if set == nil {
return errors.New(fmt.Sprintf("sourceID %s has no set", sourceID))
}
_, err = c.UpdateOne(ctx, bson.M{"source_id": set.SourceID, "session_type": sessionType}, bson.M{"$unset": updateBson})
return err
}
func (d *DataBases) GetExtendMsg(sourceID string, sessionType int32, clientMsgID string, maxMsgUpdateTime int64) (extendMsg *ExtendMsg, err error) {
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cExtendMsgSet)
findOpts := options.Find().SetLimit(1).SetSkip(0).SetSort(bson.M{"source_id": -1}).SetProjection(bson.M{fmt.Sprintf("extend_msgs.%s", clientMsgID): 1})
regex := fmt.Sprintf("^%s", sourceID)
result, err := c.Find(ctx, bson.M{"source_id": primitive.Regex{Pattern: regex}, "session_type": sessionType, "max_msg_update_time": bson.M{"$lte": maxMsgUpdateTime}}, findOpts)
if err != nil {
return nil, utils.Wrap(err, "")
}
var setList []ExtendMsgSet
if err := result.All(ctx, &setList); err != nil {
return nil, utils.Wrap(err, "")
}
if len(setList) == 0 {
return nil, utils.Wrap(errors.New("GetExtendMsg failed, len(setList) == 0"), "")
}
if v, ok := setList[0].ExtendMsgs[clientMsgID]; ok {
return &v, nil
}
return nil, errors.New(fmt.Sprintf("cant find client msg id: %s", clientMsgID))
}

View File

@ -46,10 +46,10 @@ func key(dbAddress, dbName string) string {
}
func init() {
//log.NewPrivateLog(constant.LogFileName)
var mongoClient *mongo.Client
var err1 error
//mysql init
fmt.Println("init mysql redis mongo ")
initMysqlDB()
// mongo init
// "mongodb://sysop:moon@localhost/records"
@ -84,45 +84,34 @@ func init() {
mongoClient, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri))
if err != nil {
fmt.Println(" mongo.Connect failed, try ", utils.GetSelfFuncName(), err.Error(), uri)
time.Sleep(time.Duration(30) * time.Second)
mongoClient, err1 = mongo.Connect(context.TODO(), options.Client().ApplyURI(uri))
if err1 != nil {
fmt.Println(" mongo.Connect retry failed, panic", err.Error(), uri)
panic(err1.Error())
panic(err1.Error() + " mongo.Connect failed " + uri)
}
}
fmt.Println("mongo driver client init success: ", uri)
// mongodb create index
if err := createMongoIndex(mongoClient, cSendLog, false, "send_id", "-send_time"); err != nil {
fmt.Println("send_id", "-send_time", "index create failed", err.Error())
panic(err.Error())
panic(err.Error() + " index create failed " + cSendLog + " send_id, -send_time")
}
if err := createMongoIndex(mongoClient, cChat, false, "uid"); err != nil {
fmt.Println("uid", " index create failed", err.Error())
//panic(err.Error())
fmt.Println(err.Error() + " index create failed " + cChat + " uid ")
}
if err := createMongoIndex(mongoClient, cWorkMoment, true, "-create_time", "work_moment_id"); err != nil {
fmt.Println("-create_time", "work_moment_id", "index create failed", err.Error())
panic(err.Error())
panic(err.Error() + "index create failed " + cWorkMoment + " -create_time, work_moment_id")
}
if err := createMongoIndex(mongoClient, cWorkMoment, true, "work_moment_id"); err != nil {
fmt.Println("work_moment_id", "index create failed", err.Error())
panic(err.Error())
panic(err.Error() + "index create failed " + cWorkMoment + " work_moment_id ")
}
if err := createMongoIndex(mongoClient, cWorkMoment, false, "user_id", "-create_time"); err != nil {
fmt.Println("user_id", "-create_time", "index create failed", err.Error())
panic(err.Error())
panic(err.Error() + "index create failed " + cWorkMoment + "user_id, -create_time")
}
if err := createMongoIndex(mongoClient, cTag, false, "user_id", "-create_time"); err != nil {
fmt.Println("user_id", "-create_time", "index create failed", err.Error())
panic(err.Error())
panic(err.Error() + "index create failed " + cTag + " user_id, -create_time")
}
if err := createMongoIndex(mongoClient, cTag, true, "tag_id"); err != nil {
fmt.Println("tag_id", "index create failed", err.Error())
panic(err.Error())
panic(err.Error() + "index create failed " + cTag + " tag_id")
}
fmt.Println("createMongoIndex success")
DB.mongoClient = mongoClient
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
@ -136,7 +125,8 @@ func init() {
})
_, err = DB.RDB.Ping(ctx).Result()
if err != nil {
panic(err.Error())
fmt.Println("redis cluster failed address ", config.Config.Redis.DBAddress)
panic(err.Error() + " redis cluster " + config.Config.Redis.DBUserName + config.Config.Redis.DBPassWord)
}
} else {
DB.RDB = go_redis.NewClient(&go_redis.Options{
@ -148,7 +138,7 @@ func init() {
})
_, err = DB.RDB.Ping(ctx).Result()
if err != nil {
panic(err.Error())
panic(err.Error() + " redis " + config.Config.Redis.DBAddress[0] + config.Config.Redis.DBUserName + config.Config.Redis.DBPassWord)
}
}
// 强一致性缓存当一个key被标记删除其他请求线程会被锁住轮询直到新的key生成适合各种同步的拉取, 如果弱一致可能导致拉取还是老数据,毫无意义
@ -158,6 +148,8 @@ func init() {
// 弱一致性缓存当一个key被标记删除其他请求线程直接返回该key的value适合高频并且生成很缓存很慢的情况 如大群发消息缓存的缓存
DB.WeakRc = rockscache.NewClient(DB.RDB, rockscache.NewDefaultOptions())
DB.WeakRc.Options.StrongConsistency = false
fmt.Println("init mysql redis mongo ok ")
}
func createMongoIndex(client *mongo.Client, collection string, isUnique bool, keys ...string) error {

View File

@ -10,13 +10,14 @@ import (
"context"
"errors"
"fmt"
"math/rand"
"sync"
"github.com/go-redis/redis/v8"
"github.com/gogo/protobuf/sortkeys"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"math/rand"
"sync"
//"github.com/garyburd/redigo/redis"
"github.com/golang/protobuf/proto"
@ -206,6 +207,13 @@ func (d *DataBases) ReplaceMsgBySeq(uid string, msg *open_im_sdk.MsgData, operat
return nil
}
func (d *DataBases) UpdateOneMsgList(msg *UserChat) error {
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cChat)
_, err := c.UpdateOne(ctx, bson.M{"uid": msg.UID}, bson.M{"$set": bson.M{"msg": msg.Msg}})
return err
}
func (d *DataBases) GetMsgBySeqList(uid string, seqList []uint32, operationID string) (seqMsg []*open_im_sdk.MsgData, err error) {
log.NewInfo(operationID, utils.GetSelfFuncName(), uid, seqList)
var hasSeqList []uint32
@ -291,13 +299,13 @@ func (d *DataBases) DelMongoMsgs(IDList []string) error {
return err
}
func (d *DataBases) ReplaceMsgToBlankByIndex(suffixID string, index int) error {
func (d *DataBases) ReplaceMsgToBlankByIndex(suffixID string, index int) (replaceMaxSeq uint32, err error) {
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cChat)
userChat := &UserChat{}
err := c.FindOne(ctx, bson.M{"uid": suffixID}).Decode(&userChat)
err = c.FindOne(ctx, bson.M{"uid": suffixID}).Decode(&userChat)
if err != nil {
return err
return 0, err
}
for i, msg := range userChat.Msg {
if i <= index {
@ -312,13 +320,14 @@ func (d *DataBases) ReplaceMsgToBlankByIndex(suffixID string, index int) error {
}
msg.Msg = bytes
msg.SendTime = 0
replaceMaxSeq = msgPb.Seq
}
}
_, err = c.UpdateOne(ctx, bson.M{"uid": suffixID}, bson.M{"$set": bson.M{"msg": userChat.Msg}})
return err
return replaceMaxSeq, err
}
func (d *DataBases) GetNewestMsg(ID string) (msg *MsgInfo, err error) {
func (d *DataBases) GetNewestMsg(ID string) (msg *open_im_sdk.MsgData, err error) {
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cChat)
regex := fmt.Sprintf("^%s", ID)
@ -334,13 +343,53 @@ func (d *DataBases) GetNewestMsg(ID string) (msg *MsgInfo, err error) {
}
if len(userChats) > 0 {
if len(userChats[0].Msg) > 0 {
return &userChats[0].Msg[len(userChats[0].Msg)-1], nil
msgPb := &open_im_sdk.MsgData{}
err = proto.Unmarshal(userChats[0].Msg[len(userChats[0].Msg)-1].Msg, msgPb)
if err != nil {
return nil, utils.Wrap(err, "")
}
return msgPb, nil
}
return nil, errors.New("len(userChats[0].Msg) < 0")
}
return nil, nil
}
func (d *DataBases) GetOldestMsg(ID string) (msg *open_im_sdk.MsgData, err error) {
ctx, _ := context.WithTimeout(context.Background(), time.Duration(config.Config.Mongo.DBTimeout)*time.Second)
c := d.mongoClient.Database(config.Config.Mongo.DBDatabase).Collection(cChat)
regex := fmt.Sprintf("^%s", ID)
findOpts := options.Find().SetLimit(1).SetSort(bson.M{"uid": 1})
var userChats []UserChat
cursor, err := c.Find(ctx, bson.M{"uid": bson.M{"$regex": regex}}, findOpts)
if err != nil {
return nil, err
}
err = cursor.All(ctx, &userChats)
if err != nil {
return nil, utils.Wrap(err, "")
}
var oldestMsg []byte
if len(userChats) > 0 {
for _, v := range userChats[0].Msg {
if v.SendTime != 0 {
oldestMsg = v.Msg
break
}
}
if len(oldestMsg) == 0 {
oldestMsg = userChats[0].Msg[len(userChats[0].Msg)-1].Msg
}
msgPb := &open_im_sdk.MsgData{}
err = proto.Unmarshal(oldestMsg, msgPb)
if err != nil {
return nil, utils.Wrap(err, "")
}
return msgPb, nil
}
return nil, nil
}
func (d *DataBases) GetMsgBySeqListMongo2(uid string, seqList []uint32, operationID string) (seqMsg []*open_im_sdk.MsgData, err error) {
var hasSeqList []uint32
singleCount := 0

View File

@ -22,37 +22,26 @@ func (w Writer) Printf(format string, args ...interface{}) {
}
func initMysqlDB() {
fmt.Println("init mysqlDB start")
//When there is no open IM database, connect to the mysql built-in database to create openIM database
dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=true&loc=Local",
config.Config.Mysql.DBUserName, config.Config.Mysql.DBPassword, config.Config.Mysql.DBAddress[0], "mysql")
var db *gorm.DB
var err1 error
db, err := gorm.Open(mysql.Open(dsn), nil)
if err != nil {
fmt.Println("Open failed ", err.Error(), dsn)
}
if err != nil {
time.Sleep(time.Duration(30) * time.Second)
db, err1 = gorm.Open(mysql.Open(dsn), nil)
if err1 != nil {
fmt.Println("Open failed ", err1.Error(), dsn)
panic(err1.Error())
panic(err1.Error() + " open failed " + dsn)
}
}
//Check the database and table during initialization
sql := fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s default charset utf8 COLLATE utf8_general_ci;", config.Config.Mysql.DBDatabaseName)
fmt.Println("exec sql: ", sql, " begin")
err = db.Exec(sql).Error
if err != nil {
fmt.Println("Exec failed ", err.Error(), sql)
panic(err.Error())
panic(err.Error() + " Exec failed " + sql)
}
fmt.Println("exec sql: ", sql, " end")
dsn = fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=true&loc=Local",
config.Config.Mysql.DBUserName, config.Config.Mysql.DBPassword, config.Config.Mysql.DBAddress[0], config.Config.Mysql.DBDatabaseName)
newLogger := logger.New(
Writer{},
logger.Config{
@ -66,20 +55,18 @@ func initMysqlDB() {
Logger: newLogger,
})
if err != nil {
fmt.Println("Open failed ", err.Error(), dsn)
panic(err.Error())
panic(err.Error() + " Open failed " + dsn)
}
sqlDB, err := db.DB()
if err != nil {
panic(err.Error())
panic(err.Error() + " db.DB() failed ")
}
sqlDB.SetConnMaxLifetime(time.Second * time.Duration(config.Config.Mysql.DBMaxLifeTime))
sqlDB.SetMaxOpenConns(config.Config.Mysql.DBMaxOpenConns)
sqlDB.SetMaxIdleConns(config.Config.Mysql.DBMaxIdleConns)
fmt.Println("open mysql ok ", dsn)
db.AutoMigrate(
&Register{},
&Friend{},
@ -94,99 +81,69 @@ func initMysqlDB() {
db.Set("gorm:table_options", "collation=utf8_unicode_ci")
if !db.Migrator().HasTable(&Friend{}) {
fmt.Println("CreateTable Friend")
db.Migrator().CreateTable(&Friend{})
}
if !db.Migrator().HasTable(&FriendRequest{}) {
fmt.Println("CreateTable FriendRequest")
db.Migrator().CreateTable(&FriendRequest{})
}
if !db.Migrator().HasTable(&Group{}) {
fmt.Println("CreateTable Group")
db.Migrator().CreateTable(&Group{})
}
if !db.Migrator().HasTable(&GroupMember{}) {
fmt.Println("CreateTable GroupMember")
db.Migrator().CreateTable(&GroupMember{})
}
if !db.Migrator().HasTable(&GroupRequest{}) {
fmt.Println("CreateTable GroupRequest")
db.Migrator().CreateTable(&GroupRequest{})
}
if !db.Migrator().HasTable(&User{}) {
fmt.Println("CreateTable User")
db.Migrator().CreateTable(&User{})
}
if !db.Migrator().HasTable(&Black{}) {
fmt.Println("CreateTable Black")
db.Migrator().CreateTable(&Black{})
}
if !db.Migrator().HasTable(&ChatLog{}) {
fmt.Println("CreateTable ChatLog")
db.Migrator().CreateTable(&ChatLog{})
}
if !db.Migrator().HasTable(&Register{}) {
fmt.Println("CreateTable Register")
db.Migrator().CreateTable(&Register{})
}
if !db.Migrator().HasTable(&Conversation{}) {
fmt.Println("CreateTable Conversation")
db.Migrator().CreateTable(&Conversation{})
}
if !db.Migrator().HasTable(&Department{}) {
fmt.Println("CreateTable Department")
db.Migrator().CreateTable(&Department{})
}
if !db.Migrator().HasTable(&OrganizationUser{}) {
fmt.Println("CreateTable OrganizationUser")
db.Migrator().CreateTable(&OrganizationUser{})
}
if !db.Migrator().HasTable(&DepartmentMember{}) {
fmt.Println("CreateTable DepartmentMember")
db.Migrator().CreateTable(&DepartmentMember{})
}
if !db.Migrator().HasTable(&AppVersion{}) {
fmt.Println("CreateTable DepartmentMember")
db.Migrator().CreateTable(&AppVersion{})
}
if !db.Migrator().HasTable(&BlackList{}) {
fmt.Println("CreateTable BlackList")
db.Migrator().CreateTable(&BlackList{})
}
if !db.Migrator().HasTable(&IpLimit{}) {
fmt.Println("CreateTable IpLimit")
db.Migrator().CreateTable(&IpLimit{})
}
if !db.Migrator().HasTable(&UserIpLimit{}) {
fmt.Println("CreateTable UserIpLimit")
db.Migrator().CreateTable(&UserIpLimit{})
}
if !db.Migrator().HasTable(&RegisterAddFriend{}) {
fmt.Println("CreateTable RegisterAddFriend")
db.Migrator().CreateTable(&RegisterAddFriend{})
}
if !db.Migrator().HasTable(&Invitation{}) {
fmt.Println("CreateTable Invitation")
db.Migrator().CreateTable(&Invitation{})
}
if !db.Migrator().HasTable(&ClientInitConfig{}) {
fmt.Println("CreateTable ClientInitConfig")
db.Migrator().CreateTable(&ClientInitConfig{})
}
if !db.Migrator().HasTable(&UserIpRecord{}) {
fmt.Println("CreateTable Friend")
db.Migrator().CreateTable(&UserIpRecord{})
}
DB.MysqlDB.db = db
return
}
func (m *mysqlDB) DefaultGormDB() *gorm.DB {

View File

@ -4,8 +4,6 @@ import (
"Open_IM/pkg/common/db"
"fmt"
"time"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func InsertToFriend(toInsertFollow *db.Friend) error {

View File

@ -27,7 +27,9 @@ func UpdateGroupRequest(groupRequest db.GroupRequest) error {
}
func InsertIntoGroupRequest(toInsertInfo db.GroupRequest) error {
DelGroupRequestByGroupIDAndUserID(toInsertInfo.GroupID, toInsertInfo.UserID)
if err := DelGroupRequestByGroupIDAndUserID(toInsertInfo.GroupID, toInsertInfo.UserID); err != nil {
return err
}
if toInsertInfo.HandledTime.Unix() < 0 {
toInsertInfo.HandledTime = utils.UnixSecondToTime(0)
}
@ -70,7 +72,7 @@ func GetGroupRequestByGroupID(groupID string) ([]db.GroupRequest, error) {
return groupRequestList, nil
}
//received
// received
func GetGroupApplicationList(userID string) ([]db.GroupRequest, error) {
var groupRequestList []db.GroupRequest
memberList, err := GetGroupMemberListByUserID(userID)

View File

@ -5,8 +5,6 @@ import (
"errors"
"math/rand"
"time"
"github.com/jinzhu/gorm"
)
/**
@ -89,9 +87,6 @@ func GetInvitationCode(code string) (*db.Invitation, error) {
InvitationCode: code,
}
err := db.DB.MysqlDB.DefaultGormDB().Model(invitation).Find(invitation).Error
if gorm.IsRecordNotFoundError(err) {
return invitation, nil
}
return invitation, err
}

View File

@ -3,65 +3,42 @@ package im_mysql_model
import (
"Open_IM/pkg/common/constant"
"Open_IM/pkg/common/db"
"Open_IM/pkg/common/log"
"Open_IM/pkg/utils"
"fmt"
)
func GetChatLog(chatLog db.ChatLog, pageNumber, showNumber int32) ([]db.ChatLog, error) {
var chatLogs []db.ChatLog
db := db.DB.MysqlDB.DefaultGormDB().Table("chat_logs").
Limit(int(showNumber)).Offset(int(showNumber * (pageNumber - 1)))
func GetChatLog(chatLog *db.ChatLog, pageNumber, showNumber int32, contentTypeList []int32) (int64, []db.ChatLog, error) {
mdb := db.DB.MysqlDB.DefaultGormDB().Table("chat_logs")
if chatLog.SendTime.Unix() > 0 {
db = db.Where("send_time > ? and send_time < ?", chatLog.SendTime, chatLog.SendTime.AddDate(0, 0, 1))
mdb = mdb.Where("send_time > ? and send_time < ?", chatLog.SendTime, chatLog.SendTime.AddDate(0, 0, 1))
}
if chatLog.Content != "" {
db = db.Where(" content like ? ", fmt.Sprintf("%%%s%%", chatLog.Content))
mdb = mdb.Where(" content like ? ", fmt.Sprintf("%%%s%%", chatLog.Content))
}
if chatLog.SessionType == 1 {
db = db.Where("session_type = ?", chatLog.SessionType)
mdb = mdb.Where("session_type = ?", chatLog.SessionType)
} else if chatLog.SessionType == 2 {
db = db.Where("session_type in (?)", []int{constant.GroupChatType, constant.SuperGroupChatType})
mdb = mdb.Where("session_type in (?)", []int{constant.GroupChatType, constant.SuperGroupChatType})
}
if chatLog.ContentType != 0 {
db = db.Where("content_type = ?", chatLog.ContentType)
mdb = mdb.Where("content_type = ?", chatLog.ContentType)
}
if chatLog.SendID != "" {
db = db.Where("send_id = ?", chatLog.SendID)
mdb = mdb.Where("send_id = ?", chatLog.SendID)
}
if chatLog.RecvID != "" {
db = db.Where("recv_id = ?", chatLog.RecvID)
mdb = mdb.Where("recv_id = ?", chatLog.RecvID)
}
if len(contentTypeList) > 0 {
mdb = mdb.Where("content_type in (?)", contentTypeList)
}
err := db.Find(&chatLogs).Error
return chatLogs, err
}
func GetChatLogCount(chatLog db.ChatLog) (int64, error) {
var count int64
db := db.DB.MysqlDB.DefaultGormDB().Table("chat_logs")
if chatLog.SendTime.Unix() > 0 {
log.NewDebug("", utils.GetSelfFuncName(), chatLog.SendTime, chatLog.SendTime.AddDate(0, 0, 1))
db = db.Where("send_time > ? and send_time < ?", chatLog.SendTime, chatLog.SendTime.AddDate(0, 0, 1))
if err := mdb.Count(&count).Error; err != nil {
return 0, nil, err
}
if chatLog.Content != "" {
db = db.Where(" content like ? ", fmt.Sprintf("%%%s%%", chatLog.Content))
var chatLogs []db.ChatLog
mdb = mdb.Limit(int(showNumber)).Offset(int(showNumber * (pageNumber - 1)))
if err := mdb.Find(&chatLogs).Error; err != nil {
return 0, nil, err
}
if chatLog.SessionType == 1 {
db = db.Where("session_type = ?", chatLog.SessionType)
} else if chatLog.SessionType == 2 {
db = db.Where("session_type in (?)", []int{constant.GroupChatType, constant.SuperGroupChatType})
}
if chatLog.ContentType != 0 {
db = db.Where("content_type = ?", chatLog.ContentType)
}
if chatLog.SendID != "" {
db = db.Where("send_id = ?", chatLog.SendID)
}
if chatLog.RecvID != "" {
db = db.Where("recv_id = ?", chatLog.RecvID)
}
err := db.Count(&count).Error
return count, err
return count, chatLogs, nil
}

View File

@ -8,7 +8,6 @@ import (
"Open_IM/pkg/utils"
"context"
"encoding/json"
"errors"
"fmt"
"math/big"
"sort"
@ -34,6 +33,8 @@ const (
groupMemberNumCache = "GROUP_MEMBER_NUM_CACHE:"
conversationCache = "CONVERSATION_CACHE:"
conversationIDListCache = "CONVERSATION_ID_LIST_CACHE:"
extendMsgSetCache = "EXTEND_MSG_SET_CACHE:"
extendMsgCache = "EXTEND_MSG_CACHE:"
)
func DelKeys() {
@ -408,9 +409,6 @@ func GetJoinedSuperGroupListFromCache(userID string) ([]string, error) {
if err != nil {
return "", utils.Wrap(err, "")
}
if len(userToSuperGroup.GroupIDList) == 0 {
return "", errors.New("GroupIDList == 0")
}
bytes, err := json.Marshal(userToSuperGroup.GroupIDList)
if err != nil {
return "", utils.Wrap(err, "")
@ -568,3 +566,32 @@ func GetUserAllConversationList(ownerUserID string) ([]db.Conversation, error) {
func DelConversationFromCache(ownerUserID, conversationID string) error {
return utils.Wrap(db.DB.Rc.TagAsDeleted(conversationCache+ownerUserID+":"+conversationID), "DelConversationFromCache err")
}
func GetExtendMsg(sourceID string, sessionType int32, clientMsgID string, firstModifyTime int64) (*db.ExtendMsg, error) {
getExtendMsg := func() (string, error) {
extendMsg, err := db.DB.GetExtendMsg(sourceID, sessionType, clientMsgID, firstModifyTime)
if err != nil {
return "", utils.Wrap(err, "GetExtendMsgList failed")
}
bytes, err := json.Marshal(extendMsg)
if err != nil {
return "", utils.Wrap(err, "Marshal failed")
}
return string(bytes), nil
}
extendMsgStr, err := db.DB.Rc.Fetch(extendMsgCache+clientMsgID, time.Second*30*60, getExtendMsg)
if err != nil {
return nil, utils.Wrap(err, "Fetch failed")
}
extendMsg := &db.ExtendMsg{}
err = json.Unmarshal([]byte(extendMsgStr), extendMsg)
if err != nil {
return nil, utils.Wrap(err, "Unmarshal failed")
}
return extendMsg, nil
}
func DelExtendMsg(ID string, index int32, clientMsgID string) error {
return utils.Wrap(db.DB.Rc.TagAsDeleted(extendMsgCache+clientMsgID), "DelExtendMsg err")
}

View File

@ -9,6 +9,7 @@ package kafka
import (
"context"
"fmt"
"github.com/Shopify/sarama"
)
@ -29,9 +30,10 @@ func NewMConsumerGroup(consumerConfig *MConsumerGroupConfig, topics, addrs []str
config.Version = consumerConfig.KafkaVersion
config.Consumer.Offsets.Initial = consumerConfig.OffsetsInitial
config.Consumer.Return.Errors = consumerConfig.IsReturnErr
fmt.Println("init address is ", addrs, "topics is ", topics)
//fmt.Println("init address is ", addrs, "topics is ", topics)
consumerGroup, err := sarama.NewConsumerGroup(addrs, groupID, config)
if err != nil {
fmt.Println("args:", addrs, groupID, config)
panic(err.Error())
}
return &MConsumerGroup{

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,18 @@ message AdminLoginResp {
CommonResp commonResp = 4;
}
message GetUserTokenReq {
string operationID = 1;
string userID = 2;
int32 platformID = 3;
}
message GetUserTokenResp {
CommonResp commonResp = 1;
string token = 2;
int64 expTime = 3;
}
message AddUserRegisterAddFriendIDListReq {
string operationID = 1;
repeated string userIDList = 2;
@ -62,7 +74,7 @@ message GetChatLogsReq {
int32 contentType = 6;
server_api_params.RequestPagination pagination = 7;
string operationID = 8;
string opUserID = 9;
}
message ChatLog {
@ -328,6 +340,7 @@ message GetUserIDByEmailAndPhoneNumberResp{
service adminCMS {
rpc AdminLogin(AdminLoginReq) returns(AdminLoginResp);
rpc AddUserRegisterAddFriendIDList(AddUserRegisterAddFriendIDListReq) returns(AddUserRegisterAddFriendIDListResp);
rpc ReduceUserRegisterAddFriendIDList(ReduceUserRegisterAddFriendIDListReq) returns(ReduceUserRegisterAddFriendIDListResp);
rpc GetUserRegisterAddFriendIDList(GetUserRegisterAddFriendIDListReq) returns(GetUserRegisterAddFriendIDListResp);
@ -357,4 +370,6 @@ service adminCMS {
rpc GetUserFriends(GetUserFriendsReq) returns(GetUserFriendsResp);
rpc GetUserIDByEmailAndPhoneNumber(GetUserIDByEmailAndPhoneNumberReq) returns(GetUserIDByEmailAndPhoneNumberResp);
rpc GetUserToken(GetUserTokenReq) returns(GetUserTokenResp);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
syntax = "proto3";
import "Open-IM-Server/pkg/proto/sdk_ws/ws.proto";
import "Open-IM-Server/pkg/proto/sdk_ws/wrappers.proto";
option go_package = "Open_IM/pkg/proto/msg;msg";
package msg;
@ -153,6 +154,118 @@ message GetWriteDiffMsgResp{
server_api_params.MsgData msgData = 3;
}
message ModifyMessageReactionExtensionsReq {
string operationID = 1;
string sourceID = 2;
string opUserID = 3;
int32 sessionType = 4;
map <string, server_api_params.KeyValue>reactionExtensionList = 5;
string clientMsgID = 6;
google.protobuf.StringValue ex = 7;
google.protobuf.StringValue attachedInfo = 8;
bool isReact = 9;
bool isExternalExtensions = 10;
int64 msgFirstModifyTime = 11;
}
message SetMessageReactionExtensionsReq {
string operationID = 1;
string sourceID = 2;
string opUserID = 3;
int32 sessionType = 4;
map <string, server_api_params.KeyValue>reactionExtensionList = 5;
string clientMsgID = 6;
google.protobuf.StringValue ex = 7;
google.protobuf.StringValue attachedInfo = 8;
bool isReact = 9;
bool isExternalExtensions = 10;
int64 msgFirstModifyTime = 11;
}
message SetMessageReactionExtensionsResp {
int32 errCode = 1;
string errMsg = 2;
string clientMsgID = 3;
int64 msgFirstModifyTime = 4;
bool isReact = 5;
repeated KeyValueResp result = 6;
}
message GetMessageListReactionExtensionsReq {
string operationID = 1;
string opUserID = 2;
string sourceID = 3;
int32 sessionType = 4;
bool isExternalExtensions = 5;
message MessageReactionKey {
string clientMsgID = 1;
int64 msgFirstModifyTime = 2;
}
repeated MessageReactionKey messageReactionKeyList = 6;
}
message GetMessageListReactionExtensionsResp{
int32 errCode = 1;
string errMsg = 2;
repeated SingleMessageExtensionResult singleMessageResult =3;
}
message SingleMessageExtensionResult {
int32 errCode = 1;
string errMsg = 2;
map <string, server_api_params.KeyValue>reactionExtensionList = 3;
string clientMsgID = 4;
}
message ModifyMessageReactionExtensionsResp {
int32 errCode = 1;
string errMsg = 2;
repeated ExtendMsgResp successList = 3;
repeated ExtendMsgResp failedList = 4;
}
message DeleteMessageListReactionExtensionsReq {
string operationID = 1;
string opUserID = 2;
string sourceID = 3;
int32 sessionType = 4;
string clientMsgID = 5;
bool isExternalExtensions = 6;
int64 msgFirstModifyTime = 7;
repeated server_api_params.KeyValue reactionExtensionList = 8;
}
message DeleteMessageListReactionExtensionsResp {
int32 errCode = 1;
string errMsg = 2;
repeated KeyValueResp result = 6;
}
message ExtendMsgResp {
ExtendMsg extendMsg = 1;
int32 errCode = 2;
string errMsg = 3;
}
message ExtendMsg {
map <string, KeyValueResp>reactionExtensionList = 1;
string clientMsgID = 2;
int64 msgFirstModifyTime = 3;
string attachedInfo = 4;
string ex = 5;
}
message KeyValueResp {
server_api_params.KeyValue keyValue = 1;
int32 errCode = 2;
string errMsg = 3;
}
message MsgDataToModifyByMQ{
string aggregationID = 1;
repeated MsgDataToMQ messageList = 2;
string triggerID = 3;
}
service msg {
rpc GetMaxAndMinSeq(server_api_params.GetMaxAndMinSeqReq) returns(server_api_params.GetMaxAndMinSeqResp);
@ -167,4 +280,9 @@ service msg {
rpc GetSuperGroupMsg(GetSuperGroupMsgReq) returns(GetSuperGroupMsgResp);
rpc GetWriteDiffMsg(GetWriteDiffMsgReq) returns(GetWriteDiffMsgResp);
// modify msg
rpc SetMessageReactionExtensions(SetMessageReactionExtensionsReq) returns(SetMessageReactionExtensionsResp);
rpc GetMessageListReactionExtensions(GetMessageListReactionExtensionsReq) returns(GetMessageListReactionExtensionsResp);
rpc AddMessageReactionExtensions(ModifyMessageReactionExtensionsReq) returns(ModifyMessageReactionExtensionsResp);
rpc DeleteMessageReactionExtensions(DeleteMessageListReactionExtensionsReq) returns(DeleteMessageListReactionExtensionsResp);
}

File diff suppressed because it is too large Load Diff

View File

@ -55,6 +55,8 @@ message GetUsersOnlineStatusResp{
message SuccessDetail{
string platform = 1;
string status = 2;
string connID = 3;
bool isBackground = 4;
}
message FailedDetail{
string userID = 3;
@ -89,7 +91,6 @@ message MultiTerminalLoginCheckResp{
string errMsg = 2;
}
service relay {
rpc OnlinePushMsg(OnlinePushMsgReq) returns(OnlinePushMsgResp);
rpc GetUsersOnlineStatus(GetUsersOnlineStatusReq) returns(GetUsersOnlineStatusResp);
@ -97,5 +98,6 @@ service relay {
rpc SuperGroupOnlineBatchPushOneMsg(OnlineBatchPushOneMsgReq) returns(OnlineBatchPushOneMsgResp);
rpc KickUserOffline(KickUserOfflineReq) returns(KickUserOfflineResp);
rpc MultiTerminalLoginCheck(MultiTerminalLoginCheckReq) returns(MultiTerminalLoginCheckResp);
rpc SuperGroupBackgroundOnlinePush(OnlineBatchPushOneMsgReq) returns(OnlineBatchPushOneMsgResp);
}

File diff suppressed because it is too large Load Diff

View File

@ -330,6 +330,7 @@ message GroupApplicationAcceptedTips{
GroupInfo group = 1;
GroupMemberFullInfo opUser = 2;
string handleMsg = 4;
int32 receiverAs = 5; // admin(==1) or applicant(==0)
}
// OnApplicationGroupRejected()
@ -337,6 +338,7 @@ message GroupApplicationRejectedTips{
GroupInfo group = 1;
GroupMemberFullInfo opUser = 2;
string handleMsg = 4;
int32 receiverAs = 5; // admin(==1) or applicant(==0)
}
// OnTransferGroupOwner()
@ -696,4 +698,38 @@ message DelMsgListResp{
string errMsg = 2;
}
message SetAppBackgroundStatusReq {
string userID = 1;
bool isBackground = 2;
}
message SetAppBackgroundStatusResp {
int32 errCode = 1;
string errMsg = 2;
}
message ExtendMsgSet {
string sourceID = 1;
int32 sessionType = 2;
map <string, ExtendMsg>extendMsgs = 3;
int64 MaxMsgUpdateTime = 4;
int32 extendMsgNum = 5;
int64 createTime = 6;
}
message ExtendMsg {
map <string, KeyValue>reactionExtensionList = 1;
string clientMsgID = 2;
int64 msgFirstModifyTime = 3;
string attachedInfo = 4;
string ex = 5;
}
message KeyValue {
string typeKey = 1;
string value = 2;
int64 latestUpdateTime = 3;
}

View File

@ -96,6 +96,8 @@ func GetConversationIDBySessionType(sourceID string, sessionType int) string {
return "single_" + sourceID
case constant.GroupChatType:
return "group_" + sourceID
case constant.SuperGroupChatType:
return "super_group_" + sourceID
case constant.NotificationChatType:
return "notification_" + sourceID
}

View File

@ -54,13 +54,13 @@ else
fi
#check=$(ps aux | grep -w ./${cron_task_name} | grep -v grep | wc -l)
#if [ $check -ge 1 ]; then
# echo -e ${GREEN_PREFIX}"none port has been listening,belongs service is openImCronTask"${COLOR_SUFFIX}
#else
# echo -e ${RED_PREFIX}"cron_task_name service does not start normally"${COLOR_SUFFIX}
# echo -e ${RED_PREFIX}"please check ../logs/openIM.log "${COLOR_SUFFIX}
# exit -1
#fi
#
#echo -e ${YELLOW_PREFIX}"all services launch success"${COLOR_SUFFIX}
check=$(ps aux | grep -w ./${cron_task_name} | grep -v grep | wc -l)
if [ $check -ge 1 ]; then
echo -e ${GREEN_PREFIX}"none port has been listening,belongs service is openImCronTask"${COLOR_SUFFIX}
else
echo -e ${RED_PREFIX}"cron_task_name service does not start normally"${COLOR_SUFFIX}
echo -e ${RED_PREFIX}"please check ../logs/openIM.log "${COLOR_SUFFIX}
exit -1
fi
echo -e ${YELLOW_PREFIX}"all services launch success"${COLOR_SUFFIX}

View File

@ -1,12 +1,25 @@
#!/usr/bin/env bash
source ./style_info.cfg
echo -e "check time synchronize.................................."
t=`curl http://time.akamai.com/?iso -s`
t1=`date -d $t +%s`
t2=`date +%s`
let between=t2-t1
if [[ $between -gt 10 ]] || [[ $between -lt -10 ]]; then
echo -e ${RED_PREFIX}"Warning: The difference between the iso time and the server's time is too large: "$between"s" ${COLOR_SUFFIX}
else
echo -e ${GREEN_PREFIX} "ok: Server time is synchronized " ${COLOR_SUFFIX}
fi
echo -e "check login user........................................"
user=`whoami`
if [ $user == "root" ] ; then
echo -e ${GREEN_PREFIX} "ok: login user is root" ${COLOR_SUFFIX}
echo -e ${GREEN_PREFIX} "ok: login user is root" ${COLOR_SUFFIX}
else
echo -e ${RED_PREFIX}"Warning: The current user is not root "${COLOR_SUFFIX}
echo -e ${RED_PREFIX}"Warning: The current user is not root "${COLOR_SUFFIX}
fi

View File

@ -10,7 +10,7 @@ need_to_start_server_shell=(
sdk_svr_start.sh
msg_gateway_start.sh
demo_svr_start.sh
# start_cron.sh
start_cron.sh
)
time=`date +"%Y-%m-%d %H:%M:%S"`
echo "==========================================================">>../logs/openIM.log 2>&1 &