Files
open-im-server-deploy/internal/push/push_handler.go
kim.dev.6789 e50142a3b9 复制项目
2026-01-14 22:16:44 +08:00

616 lines
25 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package push
import (
"context"
"encoding/json"
"time"
"git.imall.cloud/openim/open-im-server-deploy/internal/push/offlinepush"
"git.imall.cloud/openim/open-im-server-deploy/internal/push/offlinepush/options"
"git.imall.cloud/openim/open-im-server-deploy/pkg/common/prommetrics"
"git.imall.cloud/openim/open-im-server-deploy/pkg/common/storage/controller"
"git.imall.cloud/openim/open-im-server-deploy/pkg/common/webhook"
"git.imall.cloud/openim/open-im-server-deploy/pkg/msgprocessor"
"git.imall.cloud/openim/open-im-server-deploy/pkg/rpccache"
"git.imall.cloud/openim/open-im-server-deploy/pkg/rpcli"
"git.imall.cloud/openim/open-im-server-deploy/pkg/util/conversationutil"
"git.imall.cloud/openim/protocol/constant"
"git.imall.cloud/openim/protocol/msggateway"
pbpush "git.imall.cloud/openim/protocol/push"
"git.imall.cloud/openim/protocol/sdkws"
"github.com/openimsdk/tools/discovery"
"github.com/openimsdk/tools/log"
"github.com/openimsdk/tools/mcontext"
"github.com/openimsdk/tools/utils/datautil"
"github.com/openimsdk/tools/utils/jsonutil"
"github.com/openimsdk/tools/utils/timeutil"
"github.com/redis/go-redis/v9"
"google.golang.org/protobuf/proto"
)
type ConsumerHandler struct {
//pushConsumerGroup mq.Consumer
offlinePusher offlinepush.OfflinePusher
onlinePusher OnlinePusher
pushDatabase controller.PushDatabase
onlineCache rpccache.OnlineCache
groupLocalCache *rpccache.GroupLocalCache
conversationLocalCache *rpccache.ConversationLocalCache
webhookClient *webhook.Client
config *Config
userClient *rpcli.UserClient
groupClient *rpcli.GroupClient
msgClient *rpcli.MsgClient
conversationClient *rpcli.ConversationClient
}
func NewConsumerHandler(ctx context.Context, config *Config, database controller.PushDatabase, offlinePusher offlinepush.OfflinePusher, rdb redis.UniversalClient, client discovery.Conn) (*ConsumerHandler, error) {
userConn, err := client.GetConn(ctx, config.Discovery.RpcService.User)
if err != nil {
return nil, err
}
groupConn, err := client.GetConn(ctx, config.Discovery.RpcService.Group)
if err != nil {
return nil, err
}
msgConn, err := client.GetConn(ctx, config.Discovery.RpcService.Msg)
if err != nil {
return nil, err
}
conversationConn, err := client.GetConn(ctx, config.Discovery.RpcService.Conversation)
if err != nil {
return nil, err
}
onlinePusher, err := NewOnlinePusher(client, config)
if err != nil {
return nil, err
}
var consumerHandler ConsumerHandler
consumerHandler.userClient = rpcli.NewUserClient(userConn)
consumerHandler.groupClient = rpcli.NewGroupClient(groupConn)
consumerHandler.msgClient = rpcli.NewMsgClient(msgConn)
consumerHandler.conversationClient = rpcli.NewConversationClient(conversationConn)
consumerHandler.offlinePusher = offlinePusher
consumerHandler.onlinePusher = onlinePusher
consumerHandler.groupLocalCache = rpccache.NewGroupLocalCache(consumerHandler.groupClient, &config.LocalCacheConfig, rdb)
consumerHandler.conversationLocalCache = rpccache.NewConversationLocalCache(consumerHandler.conversationClient, &config.LocalCacheConfig, rdb)
consumerHandler.webhookClient = webhook.NewWebhookClient(config.WebhooksConfig.URL)
consumerHandler.config = config
consumerHandler.pushDatabase = database
consumerHandler.onlineCache, err = rpccache.NewOnlineCache(consumerHandler.userClient, consumerHandler.groupLocalCache, rdb, config.RpcConfig.FullUserCache, nil)
if err != nil {
return nil, err
}
return &consumerHandler, nil
}
func (c *ConsumerHandler) HandleMs2PsChat(ctx context.Context, msg []byte) {
msgFromMQ := pbpush.PushMsgReq{}
if err := proto.Unmarshal(msg, &msgFromMQ); err != nil {
log.ZError(ctx, "push Unmarshal msg err", err, "msg", string(msg))
return
}
sec := msgFromMQ.MsgData.SendTime / 1000
nowSec := timeutil.GetCurrentTimestampBySecond()
if nowSec-sec > 10 {
prommetrics.MsgLoneTimePushCounter.Inc()
log.ZWarn(ctx, "its been a while since the message was sent", nil, "msg", msgFromMQ.String(), "sec", sec, "nowSec", nowSec, "nowSec-sec", nowSec-sec)
}
var err error
switch msgFromMQ.MsgData.SessionType {
case constant.ReadGroupChatType:
err = c.Push2Group(ctx, msgFromMQ.MsgData.GroupID, msgFromMQ.MsgData)
default:
var pushUserIDList []string
isSenderSync := datautil.GetSwitchFromOptions(msgFromMQ.MsgData.Options, constant.IsSenderSync)
if !isSenderSync || msgFromMQ.MsgData.SendID == msgFromMQ.MsgData.RecvID {
pushUserIDList = append(pushUserIDList, msgFromMQ.MsgData.RecvID)
} else {
pushUserIDList = append(pushUserIDList, msgFromMQ.MsgData.RecvID, msgFromMQ.MsgData.SendID)
}
err = c.Push2User(ctx, pushUserIDList, msgFromMQ.MsgData)
}
if err != nil {
log.ZWarn(ctx, "push failed", err, "msg", msgFromMQ.String())
}
}
func (c *ConsumerHandler) WaitCache() {
c.onlineCache.WaitCache()
}
// Push2User Suitable for two types of conversations, one is SingleChatType and the other is NotificationChatType.
func (c *ConsumerHandler) Push2User(ctx context.Context, userIDs []string, msg *sdkws.MsgData) (err error) {
log.ZInfo(ctx, "Get msg from msg_transfer And push msg", "userIDs", userIDs, "msg", msg.String())
defer func(duration time.Time) {
t := time.Since(duration)
log.ZInfo(ctx, "Get msg from msg_transfer And push msg end", "msg", msg.String(), "time cost", t)
}(time.Now())
if err := c.webhookBeforeOnlinePush(ctx, &c.config.WebhooksConfig.BeforeOnlinePush, userIDs, msg); err != nil {
return err
}
wsResults, err := c.GetConnsAndOnlinePush(ctx, msg, userIDs)
if err != nil {
return err
}
log.ZDebug(ctx, "single and notification push result", "result", wsResults, "msg", msg, "push_to_userID", userIDs)
log.ZInfo(ctx, "single and notification push end")
if !c.shouldPushOffline(ctx, msg) {
return nil
}
log.ZInfo(ctx, "pushOffline start")
for _, v := range wsResults {
//message sender do not need offline push
if msg.SendID == v.UserID {
continue
}
//receiver online push success
if v.OnlinePush {
return nil
}
}
needOfflinePushUserID := []string{msg.RecvID}
var offlinePushUserID []string
//receiver offline push
if err = c.webhookBeforeOfflinePush(ctx, &c.config.WebhooksConfig.BeforeOfflinePush, needOfflinePushUserID, msg, &offlinePushUserID); err != nil {
return err
}
if len(offlinePushUserID) > 0 {
needOfflinePushUserID = offlinePushUserID
}
err = c.offlinePushMsg(ctx, msg, needOfflinePushUserID)
if err != nil {
log.ZDebug(ctx, "offlinePushMsg failed", err, "needOfflinePushUserID", needOfflinePushUserID, "msg", msg)
log.ZWarn(ctx, "offlinePushMsg failed", err, "needOfflinePushUserID length", len(needOfflinePushUserID), "msg", msg)
return nil
}
return nil
}
func (c *ConsumerHandler) shouldPushOffline(_ context.Context, msg *sdkws.MsgData) bool {
isOfflinePush := datautil.GetSwitchFromOptions(msg.Options, constant.IsOfflinePush)
if !isOfflinePush {
return false
}
switch msg.ContentType {
case constant.RoomParticipantsConnectedNotification:
return false
case constant.RoomParticipantsDisconnectedNotification:
return false
}
return true
}
func (c *ConsumerHandler) GetConnsAndOnlinePush(ctx context.Context, msg *sdkws.MsgData, pushToUserIDs []string) ([]*msggateway.SingleMsgToUserResults, error) {
if msg != nil && msg.Status == constant.MsgStatusSending {
msg.Status = constant.MsgStatusSendSuccess
}
onlineUserIDs, offlineUserIDs, err := c.onlineCache.GetUsersOnline(ctx, pushToUserIDs)
if err != nil {
return nil, err
}
log.ZDebug(ctx, "GetConnsAndOnlinePush online cache", "sendID", msg.SendID, "recvID", msg.RecvID, "groupID", msg.GroupID, "sessionType", msg.SessionType, "clientMsgID", msg.ClientMsgID, "serverMsgID", msg.ServerMsgID, "offlineUserIDs", offlineUserIDs, "onlineUserIDs", onlineUserIDs)
var result []*msggateway.SingleMsgToUserResults
if len(onlineUserIDs) > 0 {
var err error
result, err = c.onlinePusher.GetConnsAndOnlinePush(ctx, msg, onlineUserIDs)
if err != nil {
return nil, err
}
}
for _, userID := range offlineUserIDs {
result = append(result, &msggateway.SingleMsgToUserResults{
UserID: userID,
})
}
return result, nil
}
func (c *ConsumerHandler) Push2Group(ctx context.Context, groupID string, msg *sdkws.MsgData) (err error) {
log.ZInfo(ctx, "Get group msg from msg_transfer and push msg", "msg", msg.String(), "groupID", groupID, "contentType", msg.ContentType)
defer func(duration time.Time) {
t := time.Since(duration)
log.ZInfo(ctx, "Get group msg from msg_transfer and push msg end", "msg", msg.String(), "groupID", groupID, "time cost", t)
}(time.Now())
var pushToUserIDs []string
if err = c.webhookBeforeGroupOnlinePush(ctx, &c.config.WebhooksConfig.BeforeGroupOnlinePush, groupID, msg,
&pushToUserIDs); err != nil {
log.ZWarn(ctx, "Push2Group webhookBeforeGroupOnlinePush failed", err, "groupID", groupID)
return err
}
log.ZDebug(ctx, "Push2Group after webhook", "groupID", groupID, "pushToUserIDsFromWebhook", pushToUserIDs, "count", len(pushToUserIDs))
err = c.groupMessagesHandler(ctx, groupID, &pushToUserIDs, msg)
if err != nil {
log.ZWarn(ctx, "Push2Group groupMessagesHandler failed", err, "groupID", groupID)
return err
}
log.ZDebug(ctx, "Push2Group after groupMessagesHandler", "groupID", groupID, "pushToUserIDs", pushToUserIDs, "count", len(pushToUserIDs))
wsResults, err := c.GetConnsAndOnlinePush(ctx, msg, pushToUserIDs)
if err != nil {
log.ZWarn(ctx, "Push2Group GetConnsAndOnlinePush failed", err, "groupID", groupID)
return err
}
log.ZDebug(ctx, "Push2Group online push completed", "groupID", groupID, "wsResultsCount", len(wsResults))
log.ZDebug(ctx, "group push result", "result", wsResults, "msg", msg)
log.ZInfo(ctx, "online group push end")
if !c.shouldPushOffline(ctx, msg) {
return nil
}
needOfflinePushUserIDs := c.onlinePusher.GetOnlinePushFailedUserIDs(ctx, msg, wsResults, &pushToUserIDs)
//filter some user, like don not disturb or don't need offline push etc.
needOfflinePushUserIDs, err = c.filterGroupMessageOfflinePush(ctx, groupID, msg, needOfflinePushUserIDs)
if err != nil {
return err
}
log.ZInfo(ctx, "filterGroupMessageOfflinePush end")
// Use offline push messaging
if len(needOfflinePushUserIDs) > 0 {
c.asyncOfflinePush(ctx, needOfflinePushUserIDs, msg)
}
return nil
}
func (c *ConsumerHandler) asyncOfflinePush(ctx context.Context, needOfflinePushUserIDs []string, msg *sdkws.MsgData) {
var offlinePushUserIDs []string
err := c.webhookBeforeOfflinePush(ctx, &c.config.WebhooksConfig.BeforeOfflinePush, needOfflinePushUserIDs, msg, &offlinePushUserIDs)
if err != nil {
log.ZWarn(ctx, "webhookBeforeOfflinePush failed", err, "msg", msg)
return
}
if len(offlinePushUserIDs) > 0 {
needOfflinePushUserIDs = offlinePushUserIDs
}
if err := c.pushDatabase.MsgToOfflinePushMQ(ctx, conversationutil.GenConversationUniqueKeyForSingle(msg.SendID, msg.RecvID), needOfflinePushUserIDs, msg); err != nil {
log.ZDebug(ctx, "Msg To OfflinePush MQ error", err, "needOfflinePushUserIDs",
needOfflinePushUserIDs, "msg", msg)
log.ZWarn(ctx, "Msg To OfflinePush MQ error", err, "needOfflinePushUserIDs length",
len(needOfflinePushUserIDs), "msg", msg)
prommetrics.GroupChatMsgProcessFailedCounter.Inc()
return
}
}
func (c *ConsumerHandler) groupMessagesHandler(ctx context.Context, groupID string, pushToUserIDs *[]string, msg *sdkws.MsgData) (err error) {
if len(*pushToUserIDs) == 0 {
*pushToUserIDs, err = c.groupLocalCache.GetGroupMemberIDs(ctx, groupID)
if err != nil {
return err
}
switch msg.ContentType {
case constant.MemberQuitNotification:
var tips sdkws.MemberQuitTips
if unmarshalNotificationElem(msg.Content, &tips) != nil {
return err
}
if err = c.DeleteMemberAndSetConversationSeq(ctx, groupID, []string{tips.QuitUser.UserID}); err != nil {
log.ZError(ctx, "MemberQuitNotification DeleteMemberAndSetConversationSeq", err, "groupID", groupID, "userID", tips.QuitUser.UserID)
}
// 退出群聊通知只通知群主和管理员,不通知退出者本人
case constant.MemberKickedNotification:
var tips sdkws.MemberKickedTips
if unmarshalNotificationElem(msg.Content, &tips) != nil {
return err
}
kickedUsers := datautil.Slice(tips.KickedUserList, func(e *sdkws.GroupMemberFullInfo) string { return e.UserID })
if err = c.DeleteMemberAndSetConversationSeq(ctx, groupID, kickedUsers); err != nil {
log.ZError(ctx, "MemberKickedNotification DeleteMemberAndSetConversationSeq", err, "groupID", groupID, "userIDs", kickedUsers)
}
// 被踢出群聊通知只通知群主和管理员,不通知被踢出的用户本人
case constant.GroupDismissedNotification:
if msgprocessor.IsNotification(msgprocessor.GetConversationIDByMsg(msg)) {
var tips sdkws.GroupDismissedTips
if unmarshalNotificationElem(msg.Content, &tips) != nil {
return err
}
log.ZDebug(ctx, "GroupDismissedNotificationInfo****", "groupID", groupID, "num", len(*pushToUserIDs), "list", pushToUserIDs)
if len(c.config.Share.IMAdminUser.UserIDs) > 0 {
ctx = mcontext.WithOpUserIDContext(ctx, c.config.Share.IMAdminUser.UserIDs[0])
}
defer func(groupID string) {
if err := c.groupClient.DismissGroup(ctx, groupID, true); err != nil {
log.ZError(ctx, "DismissGroup Notification clear members", err, "groupID", groupID)
}
}(groupID)
}
}
}
// 过滤通知消息,只通知群主、管理员和相关成员本人
switch msg.ContentType {
case constant.GroupMemberMutedNotification, constant.GroupMemberCancelMutedNotification:
// 禁言和取消禁言:通知群主、管理员和本人
if err := c.filterNotificationWithUser(ctx, groupID, pushToUserIDs, msg, true); err != nil {
return err
}
case constant.MemberQuitNotification, constant.MemberEnterNotification, constant.GroupMemberInfoSetNotification:
// 退出、进入、成员信息设置:只通知群主和管理员
if err := c.filterNotificationWithUser(ctx, groupID, pushToUserIDs, msg, false); err != nil {
return err
}
case constant.MemberKickedNotification:
// 被踢出:通知群主、管理员和本人
if err := c.filterNotificationWithUser(ctx, groupID, pushToUserIDs, msg, true); err != nil {
return err
}
case constant.MemberInvitedNotification:
// 被邀请:通知群主、管理员和被邀请的本人
if err := c.filterNotificationWithUser(ctx, groupID, pushToUserIDs, msg, true); err != nil {
return err
}
case constant.GroupMemberSetToAdminNotification, constant.GroupMemberSetToOrdinaryUserNotification:
// 设置为管理员/普通用户:通知群主、管理员和本人
if err := c.filterNotificationWithUser(ctx, groupID, pushToUserIDs, msg, true); err != nil {
return err
}
}
return err
}
// filterNotificationWithUser 过滤通知消息,只通知群主、管理员,可选是否包含相关用户本人
// includeUser: true 表示包含相关用户本人false 表示排除相关用户
func (c *ConsumerHandler) filterNotificationWithUser(ctx context.Context, groupID string, pushToUserIDs *[]string, msg *sdkws.MsgData, includeUser bool) error {
notificationName := getNotificationName(msg.ContentType)
log.ZInfo(ctx, notificationName+" push filter start", "groupID", groupID, "originalPushToUserIDs", *pushToUserIDs, "originalCount", len(*pushToUserIDs), "includeUser", includeUser)
// 解析通知内容提取相关用户ID
var relatedUserIDs []string
var excludeUserIDs []string
switch msg.ContentType {
case constant.GroupMemberMutedNotification:
var tips sdkws.GroupMemberMutedTips
if err := unmarshalNotificationElem(msg.Content, &tips); err != nil {
log.ZWarn(ctx, notificationName+" unmarshalNotificationElem failed", err, "groupID", groupID)
return err
}
if includeUser {
relatedUserIDs = append(relatedUserIDs, tips.MutedUser.UserID)
}
log.ZDebug(ctx, notificationName+" parsed tips", "mutedUserID", tips.MutedUser.UserID, "opUserID", tips.OpUser.UserID)
case constant.GroupMemberCancelMutedNotification:
var tips sdkws.GroupMemberCancelMutedTips
if err := unmarshalNotificationElem(msg.Content, &tips); err != nil {
log.ZWarn(ctx, notificationName+" unmarshalNotificationElem failed", err, "groupID", groupID)
return err
}
if includeUser {
relatedUserIDs = append(relatedUserIDs, tips.MutedUser.UserID)
}
log.ZDebug(ctx, notificationName+" parsed tips", "cancelMutedUserID", tips.MutedUser.UserID, "opUserID", tips.OpUser.UserID)
case constant.MemberQuitNotification:
var tips sdkws.MemberQuitTips
if err := unmarshalNotificationElem(msg.Content, &tips); err != nil {
log.ZWarn(ctx, notificationName+" unmarshalNotificationElem failed", err, "groupID", groupID)
return err
}
excludeUserIDs = append(excludeUserIDs, tips.QuitUser.UserID)
log.ZDebug(ctx, notificationName+" parsed tips", "quitUserID", tips.QuitUser.UserID)
case constant.MemberInvitedNotification:
var tips sdkws.MemberInvitedTips
if err := unmarshalNotificationElem(msg.Content, &tips); err != nil {
log.ZWarn(ctx, notificationName+" unmarshalNotificationElem failed", err, "groupID", groupID)
return err
}
invitedUserIDs := datautil.Slice(tips.InvitedUserList, func(e *sdkws.GroupMemberFullInfo) string { return e.UserID })
if includeUser {
relatedUserIDs = append(relatedUserIDs, invitedUserIDs...)
} else {
excludeUserIDs = append(excludeUserIDs, invitedUserIDs...)
}
log.ZDebug(ctx, notificationName+" parsed tips", "invitedUserIDs", invitedUserIDs, "opUserID", tips.OpUser.UserID)
case constant.MemberEnterNotification:
var tips sdkws.MemberEnterTips
if err := unmarshalNotificationElem(msg.Content, &tips); err != nil {
log.ZWarn(ctx, notificationName+" unmarshalNotificationElem failed", err, "groupID", groupID)
return err
}
excludeUserIDs = append(excludeUserIDs, tips.EntrantUser.UserID)
log.ZDebug(ctx, notificationName+" parsed tips", "entrantUserID", tips.EntrantUser.UserID)
case constant.MemberKickedNotification:
var tips sdkws.MemberKickedTips
if err := unmarshalNotificationElem(msg.Content, &tips); err != nil {
log.ZWarn(ctx, notificationName+" unmarshalNotificationElem failed", err, "groupID", groupID)
return err
}
kickedUserIDs := datautil.Slice(tips.KickedUserList, func(e *sdkws.GroupMemberFullInfo) string { return e.UserID })
if includeUser {
relatedUserIDs = append(relatedUserIDs, kickedUserIDs...)
} else {
excludeUserIDs = append(excludeUserIDs, kickedUserIDs...)
}
log.ZDebug(ctx, notificationName+" parsed tips", "kickedUserIDs", kickedUserIDs, "opUserID", tips.OpUser.UserID)
case constant.GroupMemberInfoSetNotification, constant.GroupMemberSetToAdminNotification, constant.GroupMemberSetToOrdinaryUserNotification:
var tips sdkws.GroupMemberInfoSetTips
if err := unmarshalNotificationElem(msg.Content, &tips); err != nil {
log.ZWarn(ctx, notificationName+" unmarshalNotificationElem failed", err, "groupID", groupID)
return err
}
if includeUser {
relatedUserIDs = append(relatedUserIDs, tips.ChangedUser.UserID)
} else {
excludeUserIDs = append(excludeUserIDs, tips.ChangedUser.UserID)
}
log.ZDebug(ctx, notificationName+" parsed tips", "changedUserID", tips.ChangedUser.UserID, "opUserID", tips.OpUser.UserID)
default:
log.ZWarn(ctx, notificationName+" unsupported notification type", nil, "contentType", msg.ContentType)
return nil
}
// 获取所有群成员信息(如果还没有获取)
allMemberIDs := *pushToUserIDs
if len(allMemberIDs) == 0 {
var err error
allMemberIDs, err = c.groupLocalCache.GetGroupMemberIDs(ctx, groupID)
if err != nil {
log.ZWarn(ctx, notificationName+" GetGroupMemberIDs failed", err, "groupID", groupID)
return err
}
log.ZDebug(ctx, notificationName+" fetched all member IDs", "groupID", groupID, "memberCount", len(allMemberIDs))
}
members, err := c.groupLocalCache.GetGroupMembers(ctx, groupID, allMemberIDs)
if err != nil {
log.ZWarn(ctx, notificationName+" GetGroupMembers failed", err, "groupID", groupID)
return err
}
log.ZDebug(ctx, notificationName+" got members", "groupID", groupID, "memberCount", len(members))
// 筛选群主和管理员
var targetUserIDs []string
var ownerUserIDs []string
var adminUserIDs []string
for _, member := range members {
// 排除相关用户
if len(excludeUserIDs) > 0 && datautil.Contain(member.UserID, excludeUserIDs...) {
continue
}
if member.RoleLevel == constant.GroupOwner {
targetUserIDs = append(targetUserIDs, member.UserID)
ownerUserIDs = append(ownerUserIDs, member.UserID)
} else if member.RoleLevel == constant.GroupAdmin {
targetUserIDs = append(targetUserIDs, member.UserID)
adminUserIDs = append(adminUserIDs, member.UserID)
}
}
log.ZDebug(ctx, notificationName+" filtered owners and admins", "ownerCount", len(ownerUserIDs), "ownerIDs", ownerUserIDs, "adminCount", len(adminUserIDs), "adminIDs", adminUserIDs)
// 添加相关用户本人(如果需要)
if includeUser && len(relatedUserIDs) > 0 {
targetUserIDs = append(targetUserIDs, relatedUserIDs...)
log.ZDebug(ctx, notificationName+" added related users", "relatedUserIDs", relatedUserIDs, "targetCountBeforeDistinct", len(targetUserIDs))
}
// 去重并更新推送列表
*pushToUserIDs = datautil.Distinct(targetUserIDs)
log.ZInfo(ctx, notificationName+" push filter completed", "groupID", groupID, "finalPushToUserIDs", *pushToUserIDs, "finalCount", len(*pushToUserIDs), "filteredFrom", len(allMemberIDs))
return nil
}
// getNotificationName 根据通知类型获取通知名称
func getNotificationName(contentType int32) string {
switch contentType {
case constant.GroupMemberMutedNotification:
return "GroupMemberMutedNotification"
case constant.GroupMemberCancelMutedNotification:
return "GroupMemberCancelMutedNotification"
case constant.MemberQuitNotification:
return "MemberQuitNotification"
case constant.MemberInvitedNotification:
return "MemberInvitedNotification"
case constant.MemberEnterNotification:
return "MemberEnterNotification"
case constant.MemberKickedNotification:
return "MemberKickedNotification"
case constant.GroupMemberInfoSetNotification:
return "GroupMemberInfoSetNotification"
case constant.GroupMemberSetToAdminNotification:
return "GroupMemberSetToAdminNotification"
case constant.GroupMemberSetToOrdinaryUserNotification:
return "GroupMemberSetToOrdinaryUserNotification"
default:
return "UnknownNotification"
}
}
func (c *ConsumerHandler) offlinePushMsg(ctx context.Context, msg *sdkws.MsgData, offlinePushUserIDs []string) error {
title, content, opts, err := c.getOfflinePushInfos(msg)
if err != nil {
log.ZError(ctx, "getOfflinePushInfos failed", err, "msg", msg)
return err
}
err = c.offlinePusher.Push(ctx, offlinePushUserIDs, title, content, opts)
if err != nil {
prommetrics.MsgOfflinePushFailedCounter.Inc()
return err
}
return nil
}
func (c *ConsumerHandler) filterGroupMessageOfflinePush(ctx context.Context, groupID string, msg *sdkws.MsgData,
offlinePushUserIDs []string) (userIDs []string, err error) {
needOfflinePushUserIDs, err := c.conversationClient.GetConversationOfflinePushUserIDs(ctx, conversationutil.GenGroupConversationID(groupID), offlinePushUserIDs)
if err != nil {
return nil, err
}
return needOfflinePushUserIDs, nil
}
func (c *ConsumerHandler) getOfflinePushInfos(msg *sdkws.MsgData) (title, content string, opts *options.Opts, err error) {
type AtTextElem struct {
Text string `json:"text,omitempty"`
AtUserList []string `json:"atUserList,omitempty"`
IsAtSelf bool `json:"isAtSelf"`
}
opts = &options.Opts{Signal: &options.Signal{ClientMsgID: msg.ClientMsgID}}
if msg.OfflinePushInfo != nil {
opts.IOSBadgeCount = msg.OfflinePushInfo.IOSBadgeCount
opts.IOSPushSound = msg.OfflinePushInfo.IOSPushSound
opts.Ex = msg.OfflinePushInfo.Ex
}
if msg.OfflinePushInfo != nil {
title = msg.OfflinePushInfo.Title
content = msg.OfflinePushInfo.Desc
}
if title == "" {
switch msg.ContentType {
case constant.Text:
fallthrough
case constant.Picture:
fallthrough
case constant.Voice:
fallthrough
case constant.Video:
fallthrough
case constant.File:
title = constant.ContentType2PushContent[int64(msg.ContentType)]
case constant.AtText:
ac := AtTextElem{}
_ = jsonutil.JsonStringToStruct(string(msg.Content), &ac)
case constant.SignalingNotification:
title = constant.ContentType2PushContent[constant.SignalMsg]
default:
title = constant.ContentType2PushContent[constant.Common]
}
}
if content == "" {
content = title
}
return
}
func (c *ConsumerHandler) DeleteMemberAndSetConversationSeq(ctx context.Context, groupID string, userIDs []string) error {
conversationID := msgprocessor.GetConversationIDBySessionType(constant.ReadGroupChatType, groupID)
maxSeq, err := c.msgClient.GetConversationMaxSeq(ctx, conversationID)
if err != nil {
return err
}
return c.conversationClient.SetConversationMaxSeq(ctx, conversationID, userIDs, maxSeq)
}
func unmarshalNotificationElem(bytes []byte, t any) error {
var notification sdkws.NotificationElem
if err := json.Unmarshal(bytes, &notification); err != nil {
return err
}
return json.Unmarshal([]byte(notification.Detail), t)
}