Files
open-im-server/pkg/notification/msg.go
T

273 lines
12 KiB
Go
Raw Normal View History

2023-07-13 17:07:42 +08:00
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package notification
2023-06-30 09:45:02 +08:00
import (
"context"
"encoding/json"
"time"
"google.golang.org/protobuf/proto"
2024-03-05 10:51:55 +08:00
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
2024-04-19 22:23:08 +08:00
"github.com/openimsdk/protocol/constant"
"github.com/openimsdk/protocol/msg"
"github.com/openimsdk/protocol/sdkws"
"github.com/openimsdk/tools/log"
"github.com/openimsdk/tools/mq/memamq"
"github.com/openimsdk/tools/utils/idutil"
"github.com/openimsdk/tools/utils/jsonutil"
"github.com/openimsdk/tools/utils/timeutil"
2023-06-30 09:45:02 +08:00
)
2024-04-19 22:23:08 +08:00
func newContentTypeConf(conf *config.Notification) map[int32]config.NotificationConfig {
return map[int32]config.NotificationConfig{
2023-06-30 09:45:02 +08:00
// group
2024-04-19 22:23:08 +08:00
constant.GroupCreatedNotification: conf.GroupCreated,
constant.GroupInfoSetNotification: conf.GroupInfoSet,
constant.JoinGroupApplicationNotification: conf.JoinGroupApplication,
constant.MemberQuitNotification: conf.MemberQuit,
constant.GroupApplicationAcceptedNotification: conf.GroupApplicationAccepted,
constant.GroupApplicationRejectedNotification: conf.GroupApplicationRejected,
constant.GroupOwnerTransferredNotification: conf.GroupOwnerTransferred,
constant.MemberKickedNotification: conf.MemberKicked,
constant.MemberInvitedNotification: conf.MemberInvited,
constant.MemberEnterNotification: conf.MemberEnter,
constant.GroupDismissedNotification: conf.GroupDismissed,
constant.GroupMutedNotification: conf.GroupMuted,
constant.GroupCancelMutedNotification: conf.GroupCancelMuted,
constant.GroupMemberMutedNotification: conf.GroupMemberMuted,
constant.GroupMemberCancelMutedNotification: conf.GroupMemberCancelMuted,
constant.GroupMemberInfoSetNotification: conf.GroupMemberInfoSet,
constant.GroupMemberSetToAdminNotification: conf.GroupMemberSetToAdmin,
constant.GroupMemberSetToOrdinaryUserNotification: conf.GroupMemberSetToOrdinary,
constant.GroupInfoSetAnnouncementNotification: conf.GroupInfoSetAnnouncement,
constant.GroupInfoSetNameNotification: conf.GroupInfoSetName,
2023-06-30 09:45:02 +08:00
// user
2024-04-19 22:23:08 +08:00
constant.UserInfoUpdatedNotification: conf.UserInfoUpdated,
constant.UserStatusChangeNotification: conf.UserStatusChanged,
2023-06-30 09:45:02 +08:00
// friend
2024-04-19 22:23:08 +08:00
constant.FriendApplicationNotification: conf.FriendApplicationAdded,
constant.FriendApplicationApprovedNotification: conf.FriendApplicationApproved,
constant.FriendApplicationRejectedNotification: conf.FriendApplicationRejected,
constant.FriendAddedNotification: conf.FriendAdded,
constant.FriendDeletedNotification: conf.FriendDeleted,
constant.FriendRemarkSetNotification: conf.FriendRemarkSet,
constant.BlackAddedNotification: conf.BlackAdded,
constant.BlackDeletedNotification: conf.BlackDeleted,
constant.FriendInfoUpdatedNotification: conf.FriendInfoUpdated,
constant.FriendsInfoUpdateNotification: conf.FriendInfoUpdated, // use the same FriendInfoUpdated
2023-06-30 09:45:02 +08:00
// conversation
2024-04-19 22:23:08 +08:00
constant.ConversationChangeNotification: conf.ConversationChanged,
constant.ConversationUnreadNotification: conf.ConversationChanged,
constant.ConversationPrivateChatNotification: conf.ConversationSetPrivate,
2023-06-30 09:45:02 +08:00
// msg
constant.MsgRevokeNotification: {IsSendMsg: false, ReliabilityLevel: constant.ReliableNotificationNoMsg},
constant.HasReadReceipt: {IsSendMsg: false, ReliabilityLevel: constant.ReliableNotificationNoMsg},
constant.DeleteMsgsNotification: {IsSendMsg: false, ReliabilityLevel: constant.ReliableNotificationNoMsg},
2023-06-30 09:45:02 +08:00
}
}
func newSessionTypeConf() map[int32]int32 {
return map[int32]int32{
// group
2024-04-19 22:23:08 +08:00
constant.GroupCreatedNotification: constant.ReadGroupChatType,
constant.GroupInfoSetNotification: constant.ReadGroupChatType,
2023-06-30 09:45:02 +08:00
constant.JoinGroupApplicationNotification: constant.SingleChatType,
2024-04-19 22:23:08 +08:00
constant.MemberQuitNotification: constant.ReadGroupChatType,
2023-06-30 09:45:02 +08:00
constant.GroupApplicationAcceptedNotification: constant.SingleChatType,
constant.GroupApplicationRejectedNotification: constant.SingleChatType,
2024-04-19 22:23:08 +08:00
constant.GroupOwnerTransferredNotification: constant.ReadGroupChatType,
constant.MemberKickedNotification: constant.ReadGroupChatType,
constant.MemberInvitedNotification: constant.ReadGroupChatType,
constant.MemberEnterNotification: constant.ReadGroupChatType,
constant.GroupDismissedNotification: constant.ReadGroupChatType,
constant.GroupMutedNotification: constant.ReadGroupChatType,
constant.GroupCancelMutedNotification: constant.ReadGroupChatType,
constant.GroupMemberMutedNotification: constant.ReadGroupChatType,
constant.GroupMemberCancelMutedNotification: constant.ReadGroupChatType,
constant.GroupMemberInfoSetNotification: constant.ReadGroupChatType,
constant.GroupMemberSetToAdminNotification: constant.ReadGroupChatType,
constant.GroupMemberSetToOrdinaryUserNotification: constant.ReadGroupChatType,
constant.GroupInfoSetAnnouncementNotification: constant.ReadGroupChatType,
constant.GroupInfoSetNameNotification: constant.ReadGroupChatType,
2023-06-30 09:45:02 +08:00
// user
2023-08-15 19:56:41 +08:00
constant.UserInfoUpdatedNotification: constant.SingleChatType,
constant.UserStatusChangeNotification: constant.SingleChatType,
2023-06-30 09:45:02 +08:00
// friend
constant.FriendApplicationNotification: constant.SingleChatType,
constant.FriendApplicationApprovedNotification: constant.SingleChatType,
constant.FriendApplicationRejectedNotification: constant.SingleChatType,
constant.FriendAddedNotification: constant.SingleChatType,
constant.FriendDeletedNotification: constant.SingleChatType,
constant.FriendRemarkSetNotification: constant.SingleChatType,
constant.BlackAddedNotification: constant.SingleChatType,
constant.BlackDeletedNotification: constant.SingleChatType,
constant.FriendInfoUpdatedNotification: constant.SingleChatType,
2023-12-28 14:45:27 +08:00
constant.FriendsInfoUpdateNotification: constant.SingleChatType,
2023-06-30 09:45:02 +08:00
// conversation
constant.ConversationChangeNotification: constant.SingleChatType,
constant.ConversationUnreadNotification: constant.SingleChatType,
constant.ConversationPrivateChatNotification: constant.SingleChatType,
2023-07-12 15:31:24 +08:00
// delete
constant.DeleteMsgsNotification: constant.SingleChatType,
2023-06-30 09:45:02 +08:00
}
}
type NotificationSender struct {
2024-04-19 22:23:08 +08:00
contentTypeConf map[int32]config.NotificationConfig
2023-06-30 09:45:02 +08:00
sessionTypeConf map[int32]int32
sendMsg func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error)
2023-07-12 15:31:24 +08:00
getUserInfo func(ctx context.Context, userID string) (*sdkws.UserInfo, error)
2024-04-19 22:23:08 +08:00
queue *memamq.MemoryQueue
}
func WithQueue(queue *memamq.MemoryQueue) NotificationSenderOptions {
return func(s *NotificationSender) {
s.queue = queue
}
2023-06-30 09:45:02 +08:00
}
2023-07-12 15:31:24 +08:00
type NotificationSenderOptions func(*NotificationSender)
2023-06-30 09:45:02 +08:00
2023-07-13 16:51:52 +08:00
func WithLocalSendMsg(sendMsg func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error)) NotificationSenderOptions {
2023-06-30 09:45:02 +08:00
return func(s *NotificationSender) {
s.sendMsg = sendMsg
}
}
2024-12-24 10:51:38 +08:00
func WithRpcClient(sendMsg func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error)) NotificationSenderOptions {
2023-06-30 09:45:02 +08:00
return func(s *NotificationSender) {
s.sendMsg = func(ctx context.Context, req *msg.SendMsgReq) (*msg.SendMsgResp, error) {
2024-12-24 10:51:38 +08:00
return sendMsg(ctx, req)
}
2023-06-30 09:45:02 +08:00
}
}
2024-12-24 10:51:38 +08:00
func WithUserRpcClient(getUserInfo func(ctx context.Context, userID string) (*sdkws.UserInfo, error)) NotificationSenderOptions {
2023-07-12 15:31:24 +08:00
return func(s *NotificationSender) {
2024-12-24 10:51:38 +08:00
s.getUserInfo = getUserInfo
2023-07-03 16:29:22 +08:00
}
2023-07-12 15:31:24 +08:00
}
2024-04-19 22:23:08 +08:00
const (
2024-08-29 15:18:23 +08:00
notificationWorkerCount = 16
notificationBufferSize = 1024 * 1024 * 2
2024-04-19 22:23:08 +08:00
)
func NewNotificationSender(conf *config.Notification, opts ...NotificationSenderOptions) *NotificationSender {
notificationSender := &NotificationSender{contentTypeConf: newContentTypeConf(conf), sessionTypeConf: newSessionTypeConf()}
2023-06-30 09:45:02 +08:00
for _, opt := range opts {
opt(notificationSender)
}
2024-04-19 22:23:08 +08:00
if notificationSender.queue == nil {
notificationSender.queue = memamq.NewMemoryQueue(notificationWorkerCount, notificationBufferSize)
}
2023-06-30 09:45:02 +08:00
return notificationSender
}
2023-07-12 15:31:24 +08:00
type notificationOpt struct {
RpcGetUsername bool
SendNotification *bool
2023-07-12 15:31:24 +08:00
}
type NotificationOptions func(*notificationOpt)
func WithRpcGetUserName() NotificationOptions {
return func(opt *notificationOpt) {
opt.RpcGetUsername = true
}
}
func WithSendNotification(send *bool) NotificationOptions {
return func(opt *notificationOpt) {
opt.SendNotification = send
2023-07-12 15:31:24 +08:00
}
}
2024-04-19 22:23:08 +08:00
func (s *NotificationSender) send(ctx context.Context, sendID, recvID string, contentType, sessionType int32, m proto.Message, opts ...NotificationOptions) {
2024-08-29 15:18:23 +08:00
ctx = context.WithoutCancel(ctx)
2024-04-19 22:23:08 +08:00
ctx, cancel := context.WithTimeout(ctx, time.Second*time.Duration(5))
defer cancel()
n := sdkws.NotificationElem{Detail: jsonutil.StructToJsonString(m)}
2023-06-30 09:45:02 +08:00
content, err := json.Marshal(&n)
if err != nil {
2024-04-19 22:23:08 +08:00
log.ZWarn(ctx, "json.Marshal failed", err, "sendID", sendID, "recvID", recvID, "contentType", contentType, "msg", jsonutil.StructToJsonString(m))
return
2023-06-30 09:45:02 +08:00
}
2023-07-12 15:31:24 +08:00
notificationOpt := &notificationOpt{}
for _, opt := range opts {
opt(notificationOpt)
}
2023-06-30 09:45:02 +08:00
var req msg.SendMsgReq
var msg sdkws.MsgData
var userInfo *sdkws.UserInfo
if notificationOpt.RpcGetUsername && s.getUserInfo != nil {
2023-10-23 16:24:55 +08:00
userInfo, err = s.getUserInfo(ctx, sendID)
2023-07-12 15:31:24 +08:00
if err != nil {
2024-04-19 22:23:08 +08:00
log.ZWarn(ctx, "getUserInfo failed", err, "sendID", sendID)
return
2023-07-12 15:31:24 +08:00
}
2024-04-19 22:23:08 +08:00
msg.SenderNickname = userInfo.Nickname
msg.SenderFaceURL = userInfo.FaceURL
2023-07-12 15:31:24 +08:00
}
2023-06-30 09:45:02 +08:00
var offlineInfo sdkws.OfflinePushInfo
msg.SendID = sendID
msg.RecvID = recvID
msg.Content = content
msg.MsgFrom = constant.SysMsgType
msg.ContentType = contentType
2024-04-19 22:23:08 +08:00
msg.SessionType = sessionType
if msg.SessionType == constant.ReadGroupChatType {
2023-06-30 09:45:02 +08:00
msg.GroupID = recvID
}
2024-04-19 22:23:08 +08:00
msg.CreateTime = timeutil.GetCurrentTimestampByMill()
msg.ClientMsgID = idutil.GetMsgIDByMD5(sendID)
2023-09-01 21:58:23 +08:00
optionsConfig := s.contentTypeConf[contentType]
if sendID == recvID && contentType == constant.HasReadReceipt {
2023-09-01 21:58:23 +08:00
optionsConfig.ReliabilityLevel = constant.UnreliableNotification
}
options := config.GetOptionsByNotification(optionsConfig, notificationOpt.SendNotification)
s.SetOptionsByContentType(ctx, options, contentType)
2023-06-30 09:45:02 +08:00
msg.Options = options
// fill Notification OfflinePush by config
offlineInfo.Title = optionsConfig.OfflinePush.Title
offlineInfo.Desc = optionsConfig.OfflinePush.Desc
offlineInfo.Ex = optionsConfig.OfflinePush.Ext
2023-06-30 09:45:02 +08:00
msg.OfflinePushInfo = &offlineInfo
req.MsgData = &msg
_, err = s.sendMsg(ctx, &req)
if err != nil {
2024-04-19 22:23:08 +08:00
log.ZWarn(ctx, "SendMsg failed", err, "req", req.String())
2023-06-30 09:45:02 +08:00
}
}
2024-04-19 22:23:08 +08:00
func (s *NotificationSender) NotificationWithSessionType(ctx context.Context, sendID, recvID string, contentType, sessionType int32, m proto.Message, opts ...NotificationOptions) {
2024-08-26 18:15:05 +08:00
if err := s.queue.Push(func() { s.send(ctx, sendID, recvID, contentType, sessionType, m, opts...) }); err != nil {
log.ZWarn(ctx, "Push to queue failed", err, "sendID", sendID, "recvID", recvID, "msg", jsonutil.StructToJsonString(m))
}
2024-04-19 22:23:08 +08:00
}
func (s *NotificationSender) Notification(ctx context.Context, sendID, recvID string, contentType int32, m proto.Message, opts ...NotificationOptions) {
s.NotificationWithSessionType(ctx, sendID, recvID, contentType, s.sessionTypeConf[contentType], m, opts...)
2023-06-30 09:45:02 +08:00
}
func (s *NotificationSender) SetOptionsByContentType(_ context.Context, options map[string]bool, contentType int32) {
switch contentType {
case constant.UserStatusChangeNotification:
options[constant.IsSenderSync] = false
default:
}
}