From 3d34992b20e1563ae00effd7e75c1fbc6c0bd464 Mon Sep 17 00:00:00 2001 From: Robin <7434053+warrior_of_light_robin@user.noreply.gitee.com> Date: Wed, 4 Dec 2024 16:00:52 +0800 Subject: [PATCH] by Robin at 20241204 --- .../notification/proto/notification_api.go | 4 +- .../proto/notification_unread_vo_api.go | 8 +++ app/mix/dao/mongo.go | 49 ++++++++++++++ app/mix/service/apiservice.go | 30 +++++++-- app/mix/service/logic/notif_receive.go | 2 +- app/mix/service/logic/notif_recent_receive.go | 38 +++++++++++ app/mix/service/notif_bcst_center.go | 65 ++++++++++++++++--- app/mix/service/service.go | 16 +++-- app/mix/service/utilservice.go | 17 +++++ bizcommon/util/util.go | 4 ++ dbstruct/notification.go | 27 ++++++++ 11 files changed, 234 insertions(+), 26 deletions(-) create mode 100644 api/proto/notification/proto/notification_unread_vo_api.go create mode 100644 app/mix/service/logic/notif_recent_receive.go diff --git a/api/proto/notification/proto/notification_api.go b/api/proto/notification/proto/notification_api.go index e6161f42..ff466cc6 100644 --- a/api/proto/notification/proto/notification_api.go +++ b/api/proto/notification/proto/notification_api.go @@ -44,8 +44,8 @@ type ApiCountUnreadReq struct { } type ApiCountUnreadData struct { - Result map[int64]int64 `json:"result"` - Total int64 `json:"total"` + Result map[int64]*NotificationUnreadApiVO `json:"result"` + Total int64 `json:"total"` } type ApiCountUnreadResp struct { diff --git a/api/proto/notification/proto/notification_unread_vo_api.go b/api/proto/notification/proto/notification_unread_vo_api.go new file mode 100644 index 00000000..ff95e0a4 --- /dev/null +++ b/api/proto/notification/proto/notification_unread_vo_api.go @@ -0,0 +1,8 @@ +package proto + +import "service/dbstruct" + +type NotificationUnreadApiVO struct { + UnreadCnt int64 `json:"unread_cnt"` + MostRecentNotif *dbstruct.Notification `json:"most_recent_notif"` +} diff --git a/app/mix/dao/mongo.go b/app/mix/dao/mongo.go index f896431b..0210692b 100644 --- a/app/mix/dao/mongo.go +++ b/app/mix/dao/mongo.go @@ -252,6 +252,7 @@ const ( COLNotifReceiveIdSeq = "notif_receive_id_seq" COLNotifBcstIdSeq = "notif_bcst_id_seq" COLNotifReceivePull = "notif_receive_pull" + COLNotifRecentReceive = "notif_recent_receive" DBEmail = "email" COLEmail = "email" @@ -683,6 +684,11 @@ func (m *Mongo) getColNotifReceivePull() *qmgo.Collection { return m.clientMix.Database(DBNotification).Collection(COLNotifReceivePull) } +// 系统通知广播接收版本号表 +func (m *Mongo) getColNotifRecentReceive() *qmgo.Collection { + return m.clientMix.Database(DBNotification).Collection(COLNotifRecentReceive) +} + // 瑞文智商测试表 func (m *Mongo) getColRavenIQTest() *qmgo.Collection { return m.clientMix.Database(DBRavenIQTest).Collection(COLRavenIQTest) @@ -6720,6 +6726,49 @@ func (m *Mongo) CreateNotifReceivePull(ctx *gin.Context, notifReceivePull *dbstr return err } +// 通知最近接收表 +func (m *Mongo) GetNotifRecentReceive(ctx *gin.Context, id string) (recentReceive *dbstruct.NotifRecentReceive, err error) { + col := m.getColNotifRecentReceive() + + recentReceive = &dbstruct.NotifRecentReceive{} + err = col.Find(ctx, qmgo.M{"_id": id}).One(recentReceive) + if err == qmgo.ErrNoSuchDocuments { + err = nil + return nil, err + } + return recentReceive, err +} + +func (m *Mongo) GetAndUpdateNotifRecentReceive(ctx *gin.Context, id string, upd *dbstruct.NotifRecentReceive) (recentReceive *dbstruct.NotifRecentReceive, err error) { + col := m.getColNotifRecentReceive() + + // 如果库中最近接收时间小于目标接收时间,则认为应该更新 + filter := qmgo.M{ + "_id": id, + "rt": qmgo.M{ + "$lt": upd.Rt, + }, + } + + change := qmgo.Change{ + Update: qmgo.M{ + "$set": qmgo.M{ + "nid": upd.Nid, + "rt": upd.Rt, + }}, + Upsert: true, + ReturnNew: true, + } + + recentReceiveInstance := dbstruct.NotifRecentReceive{} + if err = col.Find(ctx, filter).Apply(change, &recentReceiveInstance); err != nil { + logger.Error("change error : %v", err) + return + } + + return &recentReceiveInstance, err +} + // 瑞文智商测试表相关 func (m *Mongo) CreateRavenIQTest(ctx *gin.Context, Raven_IQ_test *dbstruct.RavenIQTest) error { col := m.getColRavenIQTest() diff --git a/app/mix/service/apiservice.go b/app/mix/service/apiservice.go index 692286db..c43f90aa 100644 --- a/app/mix/service/apiservice.go +++ b/app/mix/service/apiservice.go @@ -4725,7 +4725,7 @@ func (s *Service) ApiReadAllNotification(ctx *gin.Context, req *notificationprot return } -func (s *Service) ApiGetNotificationUrcByMid(ctx *gin.Context, req *notificationproto.ApiCountUnreadReq) (mp map[int64]int64, total int64, ec errcode.ErrCode) { +func (s *Service) ApiGetNotificationUrcByMid(ctx *gin.Context, req *notificationproto.ApiCountUnreadReq) (mp map[int64]*notificationproto.NotificationUnreadApiVO, total int64, ec errcode.ErrCode) { ec = errcode.ErrCodeNotificationSrvOk // 获取apollo配置 @@ -4733,19 +4733,35 @@ func (s *Service) ApiGetNotificationUrcByMid(ctx *gin.Context, req *notification err := apollo.GetJson("n_type_map", &cfg, apollo.ApolloOpts().SetNamespace("application")) if err != nil { logger.Error("Apollo read failed : %v", err) - return make(map[int64]int64), 0, errcode.ErrCodeApolloReadFail + return make(map[int64]*notificationproto.NotificationUnreadApiVO), 0, errcode.ErrCodeApolloReadFail } // 从redis中读取数据 - mp = make(map[int64]int64) + mp = make(map[int64]*notificationproto.NotificationUnreadApiVO) if req.NType != nil { nType := util.DerefInt64(req.NType) stotal, _ := redis.GetRedisClient().GetInt64(util.GetNotifUrcIdForRedis(req.BaseRequest.Mid, nType)) - mp[nType] = stotal + notif, err := s.utilGetRecentReceiveNotif(ctx, req.BaseRequest.Mid, nType) + if err != nil { + logger.Error("utilGetRecentReceiveNotif failed : %v", err) + return make(map[int64]*notificationproto.NotificationUnreadApiVO), 0, errcode.ErrCodeNotificationSrvFail + } + mp[nType] = ¬ificationproto.NotificationUnreadApiVO{ + UnreadCnt: stotal, + MostRecentNotif: notif, + } } else { - for k := range cfg.Map { - stotal, _ := redis.GetRedisClient().GetInt64(util.GetNotifUrcIdForRedis(req.BaseRequest.Mid, k)) - mp[k] = stotal + for nType := range cfg.Map { + stotal, _ := redis.GetRedisClient().GetInt64(util.GetNotifUrcIdForRedis(req.BaseRequest.Mid, nType)) + notif, err := s.utilGetRecentReceiveNotif(ctx, req.BaseRequest.Mid, nType) + if err != nil { + logger.Error("utilGetRecentReceiveNotif failed : %v", err) + return make(map[int64]*notificationproto.NotificationUnreadApiVO), 0, errcode.ErrCodeNotificationSrvFail + } + mp[nType] = ¬ificationproto.NotificationUnreadApiVO{ + UnreadCnt: stotal, + MostRecentNotif: notif, + } } total, _ = redis.GetRedisClient().GetInt64(util.GetNotifUrcTotalIdForRedis(req.BaseRequest.Mid)) } diff --git a/app/mix/service/logic/notif_receive.go b/app/mix/service/logic/notif_receive.go index e695fcac..9391874e 100644 --- a/app/mix/service/logic/notif_receive.go +++ b/app/mix/service/logic/notif_receive.go @@ -33,7 +33,7 @@ func (p *NotifReceive) OpCreateBatch(ctx *gin.Context, notifReceives []*dbstruct return err } notifReceive.Id = notifReceiveIdSeq.Seq - notifReceive.Ct = time.Now().Unix() + //notifReceive.Ct = time.Now().Unix() // 创建时间由notification的创建时间或推送时间去决定 notifReceive.Ut = time.Now().Unix() notifReceive.DelFlag = consts.Exist } diff --git a/app/mix/service/logic/notif_recent_receive.go b/app/mix/service/logic/notif_recent_receive.go new file mode 100644 index 00000000..09e57eea --- /dev/null +++ b/app/mix/service/logic/notif_recent_receive.go @@ -0,0 +1,38 @@ +package logic + +import ( + "service/app/mix/dao" + "service/dbstruct" + "service/library/logger" + + "github.com/gin-gonic/gin" +) + +type NotifRecentReceive struct { + store *dao.Store +} + +func NewNotifRecentReceive(store *dao.Store) (a *NotifRecentReceive) { + a = &NotifRecentReceive{ + store: store, + } + return +} + +func (p *NotifRecentReceive) GetNotifRecentReceive(ctx *gin.Context, id string) (*dbstruct.NotifRecentReceive, error) { + recentReceive, err := p.store.GetNotifRecentReceive(ctx, id) + if err != nil { + logger.Error("GetNotifRecentReceive fail, err: %v", err) + return nil, err + } + return recentReceive, err +} + +func (p *NotifRecentReceive) GetAndUpdateNotifRecentReceive(ctx *gin.Context, id string, upd *dbstruct.NotifRecentReceive) (*dbstruct.NotifRecentReceive, error) { + recentReceive, err := p.store.GetAndUpdateNotifRecentReceive(ctx, id, upd) + if err != nil { + logger.Error("GetAndUpdateNotifRecentReceive fail, err: %v", err) + return nil, err + } + return recentReceive, err +} diff --git a/app/mix/service/notif_bcst_center.go b/app/mix/service/notif_bcst_center.go index fc598777..5ebdca7b 100644 --- a/app/mix/service/notif_bcst_center.go +++ b/app/mix/service/notif_bcst_center.go @@ -106,7 +106,6 @@ func (s *NotifBcstCenter) pushNotifsToMids(ctx *gin.Context, nids []int64, objMi // 查询得到消息 notifMap := make(map[int64]*dbstruct.Notification) - nTypeTotalMap := make(map[int64]int64) notifs, err := _DefaultNotification.GetListByIds(ctx, nids) if err != nil { logger.Error("GetNotificationListByIds fail, err: %v", err) @@ -114,20 +113,35 @@ func (s *NotifBcstCenter) pushNotifsToMids(ctx *gin.Context, nids []int64, objMi } for _, notif := range notifs { notifMap[notif.GetId()] = notif - nTypeTotalMap[notif.GetNType()]++ } notifReceives := make([]*dbstruct.NotifReceive, 0) + midRecentReceiveMap := make(map[int64]map[int64]*dbstruct.NotifRecentReceive) // 最近的一条通知nid for _, mid := range objMids { for _, nid := range nids { - notifReceives = append(notifReceives, &dbstruct.NotifReceive{ + notifReceive := &dbstruct.NotifReceive{ ObjMid: mid, Nid: nid, NType: notifMap[nid].GetNType(), IsRead: consts.NotifReceive_NotRead, - }) + Ct: notifMap[nid].GetRt(), + } + notifReceives = append(notifReceives, notifReceive) + s.tryToReplaceRecentReceive(midRecentReceiveMap[mid], notifReceive) } } + // 尝试更新最近接收消息记录 + for mid, recentReceiveMap := range midRecentReceiveMap { + for nType, recentReceive := range recentReceiveMap { + id := util.GetNotifRecentReceiveId(mid, nType) + _, err := _DefaultNotifRecentReceive.GetAndUpdateNotifRecentReceive(ctx, id, recentReceive) + if err != nil { + logger.Error("GetAndUpdateNotifRecentReceive fail, err: %v", err) + return err + } + } + } + err = _DefaultNotifReceive.OpCreateBatch(ctx, notifReceives) if err != nil { logger.Error("OpCreateBatch fail, err: %v", err) @@ -186,14 +200,18 @@ func (s *NotifBcstCenter) pullAllBcstedNotifs(ctx *gin.Context, vers, receiveVer if vlb < receiveVers { vlb = receiveVers } + + // 查询广播记录 notifBcsts, err := _DefaultNotifBcst.OpListByVersRange(ctx, objType, vlb, vub, 0, 1000) if err != nil { logger.Error("OpListByVersRange fail, err: %v", err) return err } + // 初始化接收表记录 notifReceives := make([]*dbstruct.NotifReceive, 0) notifReceiveMap := make(map[int64]*dbstruct.NotifReceive) nids := make([]int64, 0) + // 填充接收表记录 for _, notifBcst := range notifBcsts { for _, nid := range notifBcst.Nids { notifReceive := &dbstruct.NotifReceive{ @@ -206,19 +224,31 @@ func (s *NotifBcstCenter) pullAllBcstedNotifs(ctx *gin.Context, vers, receiveVer nids = append(nids, nid) } } - - nTypeTotalMap := make(map[int64]int64) + // 初始化最近接收记录信息 + recentReceiveMap := make(map[int64]*dbstruct.NotifRecentReceive) // 最近的一条通知nid + // 查询通知详细信息 notifs, err := _DefaultNotification.GetListByIds(ctx, nids) if err != nil { logger.Error("GetNotificationListByIds fail, err: %v", err) return err } + // 补足接收表的接收时间和消息类型 for _, notif := range notifs { - ntf, ok := notifReceiveMap[notif.GetId()] + notifReceive, ok := notifReceiveMap[notif.GetId()] if ok { - ntf.NType = notif.GetNType() + notifReceive.NType = notif.GetNType() + notifReceive.Ct = notif.GetRt() + s.tryToReplaceRecentReceive(recentReceiveMap, notifReceive) + } + } + // 尝试更新最近接收消息记录 + for nType, recentReceive := range recentReceiveMap { + id := util.GetNotifRecentReceiveId(objMid, nType) + _, err := _DefaultNotifRecentReceive.GetAndUpdateNotifRecentReceive(ctx, id, recentReceive) + if err != nil { + logger.Error("GetAndUpdateNotifRecentReceive fail, err: %v", err) + return err } - nTypeTotalMap[notif.GetNType()]++ } err = _DefaultNotifReceive.OpCreateBatch(ctx, notifReceives) @@ -346,3 +376,20 @@ func (s *NotifBcstCenter) groupOnlineMids(ctx *gin.Context) (streamerMids []int6 streamerMids, userMids = util.SplitInt64Slice(resp.Data.Mids, smids) return } + +func (s *NotifBcstCenter) tryToReplaceRecentReceive(recentReceiveMap map[int64]*dbstruct.NotifRecentReceive, notifReceive *dbstruct.NotifReceive) { + if recentReceiveMap == nil { + recentReceiveMap = make(map[int64]*dbstruct.NotifRecentReceive) + } + // 比较最近接收时间 + recentReceive, ok := recentReceiveMap[notifReceive.NType] + if ok { + if notifReceive.Ct > recentReceive.Rt { + recentReceiveMap[notifReceive.NType].Nid = notifReceive.Nid + recentReceiveMap[notifReceive.NType].Rt = notifReceive.Ct + } + } else { + recentReceiveMap[notifReceive.NType].Nid = notifReceive.Nid + recentReceiveMap[notifReceive.NType].Rt = notifReceive.Ct + } +} diff --git a/app/mix/service/service.go b/app/mix/service/service.go index ddd0989e..af9be606 100644 --- a/app/mix/service/service.go +++ b/app/mix/service/service.go @@ -159,13 +159,14 @@ var ( _DefaultRavenIQTestVisit *logic.RavenIQTestVisit _DefaultVeriCodeWrongTimes *logic.VeriCodeWrongTimes - _DefaultStreamerDecrtByEs *logic.StreamerDecrtByEs - _DefaultZoneDecrtByEs *logic.ZoneDecrtByEs - _DefaultNotifBcstVers *logic.NotifBcstVers - _DefaultNotifBcst *logic.NotifBcst - _DefaultNotifReceive *logic.NotifReceive - _DefaultNotifReceivePull *logic.NotifReceivePull - _DefaultFrontendRoute *logic.FrontendRoute + _DefaultStreamerDecrtByEs *logic.StreamerDecrtByEs + _DefaultZoneDecrtByEs *logic.ZoneDecrtByEs + _DefaultNotifBcstVers *logic.NotifBcstVers + _DefaultNotifBcst *logic.NotifBcst + _DefaultNotifReceive *logic.NotifReceive + _DefaultNotifReceivePull *logic.NotifReceivePull + _DefaultNotifRecentReceive *logic.NotifRecentReceive + _DefaultFrontendRoute *logic.FrontendRoute ) type Service struct { @@ -275,6 +276,7 @@ func (s *Service) Init(c any) (err error) { _DefaultNotifBcst = logic.NewNotifBcst(store) _DefaultNotifReceive = logic.NewNotifReceive(store) _DefaultNotifReceivePull = logic.NewNotifReceivePull(store) + _DefaultNotifRecentReceive = logic.NewNotifRecentReceive(store) _DefaultFrontendRoute = logic.NewFrontendRoute(store) _DefaultVas = logic.NewVas(store, _DefaultStreamer, _DefaultAccount, _DefaultZone, _DefaultZoneThirdPartner, _DefaultZoneCollaborator) diff --git a/app/mix/service/utilservice.go b/app/mix/service/utilservice.go index 32ff1f7d..2f0a5b7d 100644 --- a/app/mix/service/utilservice.go +++ b/app/mix/service/utilservice.go @@ -2363,3 +2363,20 @@ func (s *Service) utilDecrUrc(mid, nType, incr int64) error { } return nil } + +func (s *Service) utilGetRecentReceiveNotif(ctx *gin.Context, mid, nType int64) (*dbstruct.Notification, error) { + recentReceive, err := _DefaultNotifRecentReceive.GetNotifRecentReceive(ctx, util.GetNotifRecentReceiveId(mid, nType)) + if err != nil { + logger.Error("GetNotifRecentReceive failed : %v", err) + return nil, err + } + var notif *dbstruct.Notification + if recentReceive != nil { + notif, err = _DefaultNotification.GetListById(ctx, recentReceive.Nid) + if err != nil { + logger.Error("GetListById failed : %v", err) + return nil, err + } + } + return notif, nil +} diff --git a/bizcommon/util/util.go b/bizcommon/util/util.go index 3be66e6a..054d73f5 100644 --- a/bizcommon/util/util.go +++ b/bizcommon/util/util.go @@ -452,6 +452,10 @@ func GetNotifScene(key string, option int64) int64 { return consts.AudNotifTempKeyMap[key][option] } +func GetNotifRecentReceiveId(mid, nType int64) string { + return fmt.Sprintf("%d_%d", mid, nType) +} + func GetNotifUrcIdForRedis(mid, nType int64) string { return fmt.Sprintf("%surc_%d_%d", consts.RedisNotificationPrefix, mid, nType) } diff --git a/dbstruct/notification.go b/dbstruct/notification.go index d7fd277d..7b736058 100644 --- a/dbstruct/notification.go +++ b/dbstruct/notification.go @@ -1,6 +1,8 @@ package dbstruct import ( + "service/api/consts" + "github.com/gin-gonic/gin" ) @@ -58,6 +60,26 @@ func (p *Notification) GetNType() int64 { return 0 } +func (p *Notification) GetCt() int64 { + if p != nil && p.Ct != nil { + return *p.Ct + } + return 0 +} + +func (p *Notification) GetRt() int64 { + if p == nil { + return 0 + } + // 即时推送的通知,接收表的接收时间为其创建时间 + // 定时推送的通知,接收表的接收时间为其推送时间 + if p.GetPushTime() == consts.Notification_PushTime_Instant { + return p.GetCt() + } else { + return p.GetPushTime() + } +} + type NotifBcst struct { Id int64 `json:"id" bson:"_id"` // 通知广播表id Nids []int64 `json:"nids" bson:"nids"` // 系统通知表ids @@ -99,6 +121,11 @@ type NotifReceivePull struct { DelFlag int64 `json:"del_flag" bson:"del_flag"` // 删除标记 } +type NotifRecentReceive struct { + Nid int64 `json:"nid" bson:"nid"` // 通知表id + Rt int64 `json:"rt" bson:"rt"` // 通知接收时间 +} + type NotifBuilder struct { TemplateId int64 // 模板id TemplateParams []any // 模板参数