diff --git a/cron/cron.go b/cron/cron.go index b55c58f2f8659ff97ff3e1364e8215953b2faec8..6ea30f9fa9c3bf5314374f13c934a890f1116608 100644 --- a/cron/cron.go +++ b/cron/cron.go @@ -18,6 +18,8 @@ func Init() { group_cron.GroupPowerExpClear() // 清理家族经验/等级 group_cron.GroupPowerMonthRankAct() //group_cron.GroupInEventInit() // 进房事件 - group_cron.GroupPowerGradeExp() // 家族升级(上麦事件会用到) todo - group_cron.CreateGroup() // + group_cron.GroupPowerGradeExp() // 家族升级(上麦事件会用到) todo + group_cron.CreateGroup() // + group_cron.CalcGroupSupport() // 群组扶持计算 + group_cron.CalcGroupSupport_OldData() // 群组扶持计算-旧数据 } diff --git a/cron/gift_cron/send_gift_redis.go b/cron/gift_cron/send_gift_redis.go index cc9f581850bc858dd461b9cccccc3952247afa7c..908b17f8233f7b679f2425016d3ead4cec441e00 100644 --- a/cron/gift_cron/send_gift_redis.go +++ b/cron/gift_cron/send_gift_redis.go @@ -1,12 +1,18 @@ package gift_cron import ( + "context" + "git.hilo.cn/hilo-common/_const/rediskey" "git.hilo.cn/hilo-common/domain" "git.hilo.cn/hilo-common/resource/mysql" + "git.hilo.cn/hilo-common/resource/redisCli" + "hilo-group/_const/enum/gift_e" "hilo-group/_const/enum/groupPower_e" "hilo-group/domain/cache/gift_c" "hilo-group/domain/event/gift_ev" "hilo-group/domain/model/groupPower_m" + "hilo-group/domain/model/group_m" + "time" ) // 送礼事件 @@ -18,8 +24,9 @@ func SendGiftEvent() { for true { model := domain.CreateModelNil() if sendGiftEvent := gift_c.BLPopQueueSendGift(model); sendGiftEvent != nil { - groupPowerGrade(model, sendGiftEvent) // 家族经验 - groupPowerStar(model, sendGiftEvent) // 家族之星 + groupPowerGrade(model, sendGiftEvent) // 家族经验 + groupPowerStar(model, sendGiftEvent) // 家族之星 + groupSupportAddConsume(model, sendGiftEvent) // 群组扶持 } } }() @@ -88,3 +95,40 @@ func groupPowerStar(model *domain.Model, sendGiftEvent *gift_ev.SendGiftEvent) { } return } + +// 群组扶持增加流水数据 +func groupSupportAddConsume(model *domain.Model, sendGiftEvent *gift_ev.SendGiftEvent) { + if time.Now().Unix() <= 1692843600 { + return + } + model.Log.Infof("groupSupportAddConsume UserId:%d, sendGiftEvent:%+v", sendGiftEvent.SendUserId, sendGiftEvent) + if sendGiftEvent.SceneType != gift_e.GroupSceneType || sendGiftEvent.SceneUid == "" { + model.Log.Infof("groupSupportAddConsume UserId:%d, sendGiftEvent:%+v", sendGiftEvent.SendUserId, sendGiftEvent) + return + } + _, _, period := group_m.GetSupportLevelTime(time.Now()) + // 钻石数 + diamond := sendGiftEvent.GiftN * sendGiftEvent.ResGift.DiamondNum + keyDiamond := rediskey.GetGroupSupportConsumeSummary(period) + _, err := model.RedisCluster.ZIncrBy(context.Background(), keyDiamond, float64(diamond), sendGiftEvent.SceneUid).Result() + if err != nil { + model.Log.Errorf("groupSupportAddConsume key:%s, val:%d, member:%s, err:%v", + keyDiamond, diamond, sendGiftEvent.SceneUid, err) + } + err = redisCli.SetExpire(model.RedisCluster, keyDiamond, time.Hour*24*14) // 保留两周 + if err != nil { + model.Log.Errorf("groupSupportAddConsume key:%s, val:%d, member:%s, err:%v", + keyDiamond, diamond, sendGiftEvent.SceneUid, err) + } + // 支持者数量 + keySupportNum := rediskey.GetGroupSupportCountSupporter(period, sendGiftEvent.SceneUid) + err = model.RedisCluster.SAdd(context.Background(), keySupportNum, sendGiftEvent.SendUserId).Err() + if err != nil { + model.Log.Errorf("groupSupportAddConsume key:%s, UserId:%d, err:%v", keySupportNum, sendGiftEvent.SendUserId, err) + } + err = redisCli.SetExpire(model.RedisCluster, keySupportNum, time.Hour*24*14) // 保留两周 + if err != nil { + model.Log.Errorf("groupSupportAddConsume key:%s, UserId:%d, err:%v", keySupportNum, sendGiftEvent.SendUserId, err) + } + return +} diff --git a/cron/group_cron/group_power_month_act.go b/cron/group_cron/group_power_month_act.go index 1f6f86ec09ba336a8085843d2a5696da0bdc9df1..412b2abb4b58cdb00411de04602f8633146cf4df 100644 --- a/cron/group_cron/group_power_month_act.go +++ b/cron/group_cron/group_power_month_act.go @@ -2,12 +2,16 @@ package group_cron import ( "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/resource/config" "github.com/robfig/cron" "hilo-group/domain/service/group_power_s" ) // 家族贡献月度排行榜发奖 func GroupPowerMonthRankAct() { + if !config.IsMaster() { + return + } c := cron.New() // 每月1号0:01结算发奖 spec := "0 1 0 1 * ?" diff --git a/cron/group_cron/group_support.go b/cron/group_cron/group_support.go new file mode 100644 index 0000000000000000000000000000000000000000..e2be39b218fb60b1bd9b2bf7f07547c91e0eedfb --- /dev/null +++ b/cron/group_cron/group_support.go @@ -0,0 +1,166 @@ +package group_cron + +import ( + "context" + "encoding/json" + "git.hilo.cn/hilo-common/_const/rediskey" + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/resource/config" + "git.hilo.cn/hilo-common/resource/redisCli" + "git.hilo.cn/hilo-common/sdk/tencentyun" + "git.hilo.cn/hilo-common/utils" + "github.com/robfig/cron" + "hilo-group/_const/enum/gift_e" + "hilo-group/_const/enum/group_e" + "hilo-group/domain/model/gift_m" + "hilo-group/domain/model/group_m" + "hilo-group/domain/service/group_s" + "time" +) + +// 群组扶持计算 +func CalcGroupSupport() { + if !config.IsMaster() { + return + } + c := cron.New() + //北京时间周一0点,过了一秒后, + spec := "1 0 0 * * 1" + _ = c.AddFunc(spec, func() { + defer utils.CheckGoPanic() + var model = domain.CreateModelNil() + //开始 + model.Log.Infof("cron CalcGroupSupport start") + + calcTime := time.Now().AddDate(0, 0, -1) + if err := group_s.NewGroupService(model.MyContext).GroupSupportResult(calcTime); err != nil { + model.Log.Errorf("cron CalcGroupSupport faild calcTime:%v, err:%v", calcTime, err) + return + } + model.Log.Infof("cron CalcGroupSupport after GroupSupportResult") + + //全服发送H5 + if err := sendGroupSupportH5(domain.CreateModelContext(model.MyContext)); err != nil { + model.Log.Errorf("cron CalcGroupSupport err:%v", err) + } else { + model.Log.Infof("cron CalcGroupSupport success") + } + }) + + c.Start() +} + +func sendGroupSupportH5(model *domain.Model) error { + groupIds, err := group_m.GetAllGroupsSorted(model) + if err != nil { + return err + } + + model.Log.Infof("SendGroupSupportH5 groupIds:%v", groupIds) + + groupSupportH5 := group_m.GroupSupportH5{ + CommonPublicMsg: group_m.CommonPublicMsg{ + Type: group_e.GroupSupportH5, + }, + H5: config.GetH5Config().GROUP_SUPPORT, + } + buffer, err := json.Marshal(groupSupportH5) + if err != nil { + model.Log.Errorf("publicScreenMsg AddSendGiftAsync json.Marshal(giftContent) err:%v", err) + return err + } + content := string(buffer) + + //策略1:for循环,没有开启协程,100个停一下 + for i, _ := range groupIds { + func(groupId string, content string) { + defer utils.CheckGoPanic() + model.Log.Infof("SendGroupSupportH5 groupId:%v", groupId) + txGroupId, err := group_m.ToTxGroupId(model, groupId) + // 公屏消息 + if err == nil { + tencentyun.SendCustomMsg(model.Log, txGroupId, nil, content, "") + } + }(groupIds[i], content) + + if i != 0 && i%100 == 0 { + //躺平1秒 + time.Sleep(1 * time.Second) + } + } + return nil +} + +// 群组扶持计算-本周旧数据 +func CalcGroupSupport_OldData() { + if !config.IsMaster() { + return + } + c := cron.New() + spec := "0 30 10 24 8 ?" + _ = c.AddFunc(spec, func() { + defer utils.CheckGoPanic() + var model = domain.CreateModelNil() + //开始 + model.Log.Infof("CalcGroupSupport_OldData start") + + beginTime, _, period := group_m.GetSupportLevelTime(time.Now()) + endTime := time.Unix(1692843600, 0) + + g := gift_m.GiftOperate{SceneType: gift_e.GroupSceneType, Model: model} + records, err := g.BatchGetConsumeByRange(beginTime, endTime) + if err != nil { + model.Log.Errorf("CalcGroupSupport_OldData beginTime:%v, endTime:%v, err:%v", beginTime, endTime, err) + return + } + // 流水写入redis + keyDiamond := rediskey.GetGroupSupportConsumeSummary(period) + for _, r := range records { + if r.SceneUid == "" || r.Consume <= 0 { + continue + } + _, err = model.RedisCluster.ZIncrBy(context.Background(), keyDiamond, float64(r.Consume), r.SceneUid).Result() + if err != nil { + model.Log.Errorf("CalcGroupSupport_OldData groupSupport key:%s, val:%d, member:%s, err:%v", + keyDiamond, r.Consume, r.SceneUid, err) + } + } + err = redisCli.SetExpire(model.RedisCluster, keyDiamond, time.Hour*24*14) // 保留两周 + if err != nil { + model.Log.Errorf("CalcGroupSupport_OldData groupSupport key:%s, err:%v", keyDiamond, err) + return + } + // 支持者写入redis + for _, r := range records { + if r.SceneUid == "" || r.C <= 0 { + continue + } + // 支持者列表 + support := gift_m.GiftOperate{SceneType: gift_e.GroupSceneType, SceneUid: r.SceneUid, Model: model} + uids, err := support.BatchGetSupportList(beginTime, endTime) + if err != nil { + model.Log.Errorf("CalcGroupSupport_OldData beginTime:%v, endTime:%v, imGroupId:%v, err:%v", beginTime, endTime, r.SceneUid, err) + continue + } + if len(uids) <= 0 { + continue + } + // 支持者数量 + keySupportNum := rediskey.GetGroupSupportCountSupporter(period, r.SceneUid) + for _, uid := range uids { + err = model.RedisCluster.SAdd(context.Background(), keySupportNum, uid).Err() + if err != nil { + model.Log.Errorf("CalcGroupSupport_OldData groupSupport key:%s, UserId:%d, err:%v", keySupportNum, uid, err) + } + } + err = redisCli.SetExpire(model.RedisCluster, keySupportNum, time.Hour*24*14) // 保留两周 + if err != nil { + model.Log.Errorf("AddSendGiftEventAsync groupSupport key:%s, err:%v", keySupportNum, err) + } + } + + model.Log.Infof("CalcGroupSupport_OldData end") + }) + + c.Start() +} diff --git a/debug.ini b/debug.ini index 3205478c8644930029b550d4078412daa9ddc844..6ab0d1dc68aaf35f6d6b0a3b899938ec56cb2b12 100644 --- a/debug.ini +++ b/debug.ini @@ -11,6 +11,8 @@ MYSQL_DB=hilo_code [REDIS] REDIS_HOST=47.244.34.27:6379 REDIS_PASSWORD=8QZ9JD1zLvPR3yHf +REDIS_CLUSTER_HOST=47.244.34.27:6379 +REDIS_CLUSTER_PASSWORD=8QZ9JD1zLvPR3yHf [JWT] SECRET=hilo1632 ISSUER_API=hiloApi diff --git a/domain/model/gift_m/gift.go b/domain/model/gift_m/gift.go index 51ebce135c3ce2fb2464e0e2ee8db7ba6b178d41..6c7140314be89e11ad0c08ecbcf9c51f97b7b973 100644 --- a/domain/model/gift_m/gift.go +++ b/domain/model/gift_m/gift.go @@ -182,6 +182,17 @@ func (g *GiftOperate) BatchGetConsumeByRange(beginTime, endTime time.Time) ([]Sc return rows, nil } +func (g *GiftOperate) BatchGetSupportList(beginTime, endTime time.Time) ([]uint64, error) { + userIds := make([]uint64, 0) + err := g.DB().Model(g). + Select("DISTINCT(send_user_id) AS user_id"). + Where(g).Where("created_time BETWEEN ? AND ?", beginTime, endTime).Pluck("user_id", &userIds).Error + if err != nil { + return nil, err + } + return userIds, nil +} + func SumSendGift(model *domain.Model, sendUserId mysql.ID, giftId mysql.ID) (uint32, error) { type Result struct { N uint32 diff --git a/domain/service/group_s/group_support.go b/domain/service/group_s/group_support.go index fe63bd1b2c8754cd6abcffe015161ce7d5727151..c3202c76cdbdecabeba174c1ee9479974278e8d5 100644 --- a/domain/service/group_s/group_support.go +++ b/domain/service/group_s/group_support.go @@ -1,14 +1,22 @@ package group_s import ( + "context" + "git.hilo.cn/hilo-common/_const/enum/msg_e" + "git.hilo.cn/hilo-common/_const/rediskey" "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/resource/mysql" + "git.hilo.cn/hilo-common/resource/redisCli" + "github.com/go-redis/redis/v8" "hilo-group/_const/enum/gift_e" "hilo-group/domain/event/group_ev" "hilo-group/domain/model/gift_m" "hilo-group/domain/model/group_m" + "hilo-group/domain/model/msg_m" "hilo-group/domain/model/res_m" "hilo-group/domain/model/user_m" "hilo-group/myerr/bizerr" + "strconv" "time" ) @@ -173,3 +181,128 @@ func (s *GroupService) RenewGroupSupporter(groupId string, userIds []uint64) err return nil }) } + +func (s *GroupService) GroupSupportResult(time time.Time) error { + model := domain.CreateModelContext(s.svc.MyContext) + + _, _, period := group_m.GetSupportLevelTime(time) + // 群组扶持数值 + groupGradeMap, err := getGroupGradeMap(model, period) + if err != nil { + model.Log.Errorf("GroupSupportResult time:%v, err:%v", time, err) + return err + } + + model.Log.Infof("GroupSupportResult period:%s, len:%d, groupUidGadeMap:%v", period, len(groupGradeMap), groupGradeMap) + // 房间访问人数 + roomVisitCount, err := GetAllRoomNonZeroVisitCount() + if err != nil { + model.Log.Errorf("GroupSupportResult err:%v", err) + return err + } + + // 入库群组扶持结果 + for g, grade := range groupGradeMap { + r := group_m.InitGroupSupportResult(model, g, grade, period, roomVisitCount[g]) + r.SetOnDuplicateKeyIGNORE() + if err = r.Persistent(); err != nil { + model.Log.Errorf("GroupSupportResult InitGroupSupportResult r:%+v, err:%v", r, err) + } + } + // 小助手通知 + AssistantNotification(model, groupGradeMap) + return nil +} + +func getGroupGradeMap(model *domain.Model, period string) (map[string]uint8, error) { + // 配置 + gsConfig, err := res_m.GetResGroupSupportByValid(model) + if err != nil { + model.Log.Errorf("GroupSupportResult err:%v", err) + return nil, err + } + + // 群组扶持数值 + groupGradeMap := make(map[string]uint8, 0) + //userNum := make(map[string]uint32, 0) + + // 流水 + keyDiamond := rediskey.GetGroupSupportConsumeSummary(period) + var start int64 + count := int64(999) + var zList []redis.Z + // 一次取1000个处理 + for start == 0 || len(zList) > 0 { + stop := start + count + zList, err = model.RedisCluster.ZRangeWithScores(context.Background(), keyDiamond, start, stop).Result() + if err != nil { + model.Log.Errorf("GroupSupportResult err:%v", err) + return nil, err + } + if len(zList) == 0 { + break + } + for _, v := range zList { + imGroupId := v.Member.(string) + consume := mysql.Num(v.Score) + // 支持者数量 + keySupportNum := rediskey.GetGroupSupportCountSupporter(period, imGroupId) + supportNum, err := model.RedisCluster.SCard(context.Background(), keySupportNum).Result() + if err != nil { + model.Log.Errorf("GroupSupportResult key:%s, err:%v", keySupportNum, err) + return nil, err + } + for j := len(gsConfig) - 1; j >= 0; j-- { + if mysql.Num(supportNum) >= gsConfig[j].ContributeUserNum && consume >= gsConfig[j].ContributeDiamondNum { + groupGradeMap[imGroupId] = gsConfig[j].Grade + //userNum[imGroupId] = uint32(supportNum) + break + } + } + } + start = stop + 1 + } + return groupGradeMap, nil +} + +func AssistantNotification(model *domain.Model, groupGradeMap map[string]uint8) { + // 小助手通知 + for g, _ := range groupGradeMap { + userId, err := group_m.GetProfitAllocator(model, g) + if err != nil { + model.Log.Errorf("GroupSupportResult msg GetProfitAllocator err:%v, groupUid:%v", err, g) + continue + } + //推送 + user, err := user_m.GetUser(model, userId) + if err != nil { + model.Log.Infof("GroupSupportResult msg GetUser userId:=%v, err:=%v", userId, err) + continue + } + record := msg_m.NewUserRecord(model, user.ID, msg_e.GroupSupportResult, "", 0, "", "", "", "", "") + if err := record.Persistent(); err != nil { + model.Log.Infof("GroupSupportResult msg record.Persistent() err:%v", err) + continue + } + msg_m.SendEmasMsgAssistant(model, user.ExternalId, user.DeviceType) + } +} + +func GetAllRoomNonZeroVisitCount() (map[string]uint, error) { + m, err := GetAllRoomVisitCount() + if err != nil { + return nil, err + } + result := make(map[string]uint, 0) + for g, s := range m { + if c, err := strconv.Atoi(s); err == nil && c > 0 { + result[g] = uint(c) + } + } + return result, nil +} + +func GetAllRoomVisitCount() (map[string]string, error) { + key := rediskey.GetPrefixRoomVisitCount() + return redisCli.GetRedis().HGetAll(context.Background(), key).Result() +} diff --git a/main.go b/main.go index 629b87e7f36d403160294b1a598fb2912dd42349..055e546be9a5095f6b09402732cc5f42798d42d4 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,7 @@ package main import ( "fmt" "git.hilo.cn/hilo-common/resource/consul" + "git.hilo.cn/hilo-common/resource/redisCli" "hilo-group/cron" "hilo-group/domain/service/event_s" "hilo-group/route" @@ -17,6 +18,7 @@ const ( func main() { cron.Init() // 开启定时任务 event_s.EventInit() // 注册事件(内部事件+mysql拟kafka) + redisCli.InitCluster() // redis集群 r := route.InitRouter() // 注册路由 consul.RegisterToConsul(PORT, RegisterName, RegisterTag) // 服务注册 r.Run(fmt.Sprintf(":%d", PORT)) // 启动服务 diff --git a/release.ini b/release.ini index 64eee6d6ada4cb0fcbd7b7dfa58cf001eee1552d..23f6172f43eca43cd4970b733b5d85927960ce83 100644 --- a/release.ini +++ b/release.ini @@ -11,6 +11,8 @@ MYSQL_DB=hilo_code [REDIS] REDIS_HOST=r-eb3btxn8vfdsuwdbuf.redis.dubai.rds.aliyuncs.com:6379 REDIS_PASSWORD= +REDIS_CLUSTER_HOST=r-eb3yt6k8zgxs62kjjs.redis.dubai.rds.aliyuncs.com:6379 +REDIS_CLUSTER_PASSWORD= [JWT] SECRET=hilo1504 ISSUER_API=hiloApi