Commit f34d8846 authored by chenweijian's avatar chenweijian

群组优化

parent 80137d5c
...@@ -19,7 +19,8 @@ func Init() { ...@@ -19,7 +19,8 @@ func Init() {
group_cron.GroupPowerExpClear() // 清理家族经验/等级 group_cron.GroupPowerExpClear() // 清理家族经验/等级
group_cron.GroupPowerMonthRankAct() group_cron.GroupPowerMonthRankAct()
//group_cron.GroupInEventInit() // 进房事件 //group_cron.GroupInEventInit() // 进房事件
group_cron.CreateGroup() // //group_cron.CreateGroup() //
group_cron.CalcGroupSupport() // 群组扶持计算 group_cron.CalcGroupSupport() // 群组扶持计算
//group_cron.CalcGroupSupport_OldData() //group_cron.CalcGroupSupport_OldData()
group_cron.GroupCountryListSort()
} }
...@@ -111,7 +111,7 @@ func groupSupportAddConsume(model *domain.Model, sendGiftEvent *gift_ev.SendGift ...@@ -111,7 +111,7 @@ func groupSupportAddConsume(model *domain.Model, sendGiftEvent *gift_ev.SendGift
} }
_, _, period := group_m.GetSupportLevelTime(time.Now()) _, _, period := group_m.GetSupportLevelTime(time.Now())
// 钻石数 // 钻石数
diamond := sendGiftEvent.GiftN * sendGiftEvent.ResGift.DiamondNum diamond := sendGiftEvent.GiftN * sendGiftEvent.ResGift.DiamondNum * mysql.Num(len(sendGiftEvent.ReceiveUserIds))
keyDiamond := rediskey.GetGroupSupportConsumeSummary(period) keyDiamond := rediskey.GetGroupSupportConsumeSummary(period)
_, err := model.RedisCluster.ZIncrBy(context.Background(), keyDiamond, float64(diamond), sendGiftEvent.SceneUid).Result() _, err := model.RedisCluster.ZIncrBy(context.Background(), keyDiamond, float64(diamond), sendGiftEvent.SceneUid).Result()
if err != nil { if err != nil {
......
package group_cron
import (
"git.hilo.cn/hilo-common/domain"
"github.com/robfig/cron"
"hilo-group/domain/service/group_s"
)
// 清理家族经验和等级
func GroupCountryListSort() {
// 常用国家-每15分钟计算国家房间列表排序 /v1/imGroup/country [get] 接口
spec := "0 */15 * * * ?"
c := cron.New()
_ = c.AddFunc(spec, func() {
var model = domain.CreateModelNil()
group_s.SortGroupCommonCountryList(model)
})
// 非常用国家-每60分钟计算国家房间列表排序 /v1/imGroup/country [get] 接口
spec2 := "0 15 * * * ?"
_ = c.AddFunc(spec2, func() {
var model = domain.CreateModelNil()
group_s.SortGroupNotCommonCountryList(model)
})
c.Start()
}
...@@ -213,3 +213,10 @@ func GetLangeByCountry(db *gorm.DB, country mysql.Str) (string, error) { ...@@ -213,3 +213,10 @@ func GetLangeByCountry(db *gorm.DB, country mysql.Str) (string, error) {
return "", myerr.WrapErr(err) return "", myerr.WrapErr(err)
} }
} }
//获取所有国家名字列表
func GetCountryNameList(model *domain.Model) ([]string, error) {
res := make([]string, 0)
err := model.DB().Select("distinct(name) name").Pluck("name", &res).Error
return res, myerr.WrapErr(err)
}
package group_s
import (
"context"
"git.hilo.cn/hilo-common/_const/rediskey"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/redisCli"
"github.com/go-redis/redis/v8"
"hilo-group/_const/enum/gift_e"
"hilo-group/cv/gift_cv"
"hilo-group/domain/cache/room_c"
"hilo-group/domain/model/group_m"
"hilo-group/domain/model/res_m"
"sort"
"strconv"
"time"
)
func SortGroupCommonCountryList(model *domain.Model) {
// 常用的国家
countryMap := map[string]struct{}{"India": {}, "Indonesia": {}, "Iraq": {}, "KSA": {}, "Kuwait": {}, "Pakistan": {}, "Turkey": {}}
for country, _ := range countryMap {
sortGroupList, err := GetGroupSortList(model, country)
if err != nil {
model.Log.Errorf("SortGroupCommonCountryList err:%v", err)
return
}
// 写入redis
err = setToRedis(model, country, sortGroupList)
if err != nil {
model.Log.Errorf("SortGroupCommonCountryList country:%v, len(sortGroupList):%v, err:%v", country, len(sortGroupList), err)
return
}
time.Sleep(time.Second * 3)
}
}
func SortGroupNotCommonCountryList(model *domain.Model) {
// 常用的国家
countryMap := map[string]struct{}{"India": {}, "Indonesia": {}, "Iraq": {}, "KSA": {}, "Kuwait": {}, "Pakistan": {}, "Turkey": {}}
// 取所有的国家名字
allCountryList, err := res_m.GetCountryNameList(model)
if err != nil {
model.Log.Errorf("SortGroupNotCommonCountryList err:%v", err)
return
}
for _, country := range allCountryList {
if _, ok := countryMap[country]; ok {
continue
}
// 计算非常用国家
sortGroupList, err := GetGroupSortList(model, country)
if err != nil {
model.Log.Errorf("SortGroupNotCommonCountryList err:%v", err)
return
}
// 写入redis
err = setToRedis(model, country, sortGroupList)
if err != nil {
model.Log.Errorf("SortGroupNotCommonCountryList country:%v, len(sortGroupList):%v, err:%v", country, len(sortGroupList), err)
return
}
time.Sleep(time.Second * 5)
}
}
func setToRedis(model *domain.Model, country string, groupList []string) error {
// 写入redis
key := rediskey.GetGroupCountrySortList(country)
for idx, group := range groupList {
err := redisCli.GetRedis().ZRemRangeByRank(context.Background(), key, int64(idx), int64(idx)).Err() // 先删除旧的
if err != nil {
model.Log.Errorf("setToRedis SortGroup key:%v, idx:%v, err:%v", key, idx, err)
return err
}
// 插入
err = redisCli.GetRedis().ZAdd(context.Background(), key, &redis.Z{Score: float64(idx), Member: group}).Err()
if err != nil {
model.Log.Errorf("setToRedis SortGroup key:%v, idx:%v, group:%s, err:%v", key, idx, group, err)
return err
}
if idx%1000 == 0 {
time.Sleep(time.Millisecond * 50)
}
}
return nil
}
// 计算国家群组列表排序
func GetGroupSortList(model *domain.Model, country string) ([]string, error) {
bannedGroups, err := group_m.GetBannedGroupsMap(model)
if err != nil {
return nil, err
}
beginTime := time.Now()
groups, banCount, visitCount, err := GetCandidatesByCountry(model, bannedGroups, country)
if err != nil {
return nil, err
}
endTime := time.Now()
model.Log.Infof("GroupCountryListSort: candidates size = %d, takes %d ms banned = %d, visitCount size = %d",
len(groups), endTime.Sub(beginTime).Milliseconds(), banCount, len(visitCount))
// 获取麦上有人的所有群组及麦上人数
micGroupNum, err := group_m.GetMicHasInGroupNum(model)
if err != nil {
return nil, err
}
model.Log.Infof("GroupCountryListSort, micGroupNum : %v", micGroupNum)
model.Log.Infof("GroupCountryListSort cost2:%v", time.Now().Sub(beginTime))
sortedGroupIds := make([]string, 0)
diamondGroupIds := make([]string, 0)
for i, _ := range groups {
// 麦上没人也放出来
sortedGroupIds = append(sortedGroupIds, i)
// 麦上有人才计算流水
if micGroupNum[i] > 0 {
diamondGroupIds = append(diamondGroupIds, i)
}
}
now := time.Now()
bTime := now.Add(-time.Minute * 30)
g := gift_cv.GiftOperate{SceneType: gift_e.GroupSceneType}
diamonds, err := g.GetRangeConsumeSummaryV2(bTime, now, diamondGroupIds)
if err != nil {
return nil, err
}
model.Log.Infof("GroupCountryListSort, diamonds in 30 mins: %v", diamonds)
model.Log.Infof("GroupCountryListSort cost3:%v", time.Now().Sub(beginTime))
supportLevels, err := NewGroupService(model.MyContext).GetWeekMaxSupportLevelMap()
if err != nil {
return nil, err
}
model.Log.Infof("GroupCountryListSort, supportLevels : %v", supportLevels)
model.Log.Infof("GroupCountryListSort cost4:%v", time.Now().Sub(beginTime))
// 排序优先级2022-07-25
sort.Slice(sortedGroupIds, func(i, j int) bool {
gi := sortedGroupIds[i]
gj := sortedGroupIds[j]
// 1、按麦上人数多少排序
if micGroupNum[gi] > micGroupNum[gj] {
return true
} else if micGroupNum[gi] < micGroupNum[gj] {
return false
}
// 2、麦上人数相同,按30分钟内送礼钻石数排序
if diamonds[gi] > diamonds[gj] {
return true
} else if diamonds[gi] < diamonds[gj] {
return false
}
// 3. 根据热度排序groupInUserDuration
if visitCount[gi] > visitCount[gj] {
return true
} else if visitCount[gi] < visitCount[gj] {
return false
}
// * Final resort: 群组CODE,短号优先,然后按字母序
return len(groups[gi].Code) < len(groups[gj].Code) || len(groups[gi].Code) == len(groups[gj].Code) && groups[gi].Code < groups[gj].Code
})
model.Log.Infof("GroupCountryListSort cost5:%v", time.Now().Sub(beginTime))
return sortedGroupIds, nil
}
// 国家群候选:没有密码且没被封禁的群, 有国家
func GetCandidatesByCountry(model *domain.Model, bannedGroups map[string]uint64, country string) (map[string]*group_m.GroupInfo, int, map[string]int64, error) {
noPwdGroups, err := group_m.FindOwnerCountryGroups(model, country)
if err != nil {
return nil, 0, nil, err
}
var groupIds []string
for _, v := range noPwdGroups {
groupIds = append(groupIds, v.ImGroupId) // imGroupId
}
//roomVisitCount, err := room_c.GetAllRoomVisitCount()
roomVisitCount, err := room_c.MGetRoomVisitCount(groupIds)
if err != nil {
return nil, 0, nil, err
}
gameRoom := group_m.GetGameGroupsMap(model)
banCount := 0
groups := make(map[string]*group_m.GroupInfo, 0)
visitCount := make(map[string]int64)
for i, v := range noPwdGroups {
// 过滤掉被封禁的群
if bannedGroups[v.ImGroupId] != 0 {
banCount++
continue
}
// 过滤游戏房
if gameRoom[v.ImGroupId] {
continue
}
// 先从二级缓存中找
if c, ok := roomVisitCount[v.ImGroupId]; ok {
if vc, err := strconv.ParseInt(c, 10, 64); err == nil && vc > 0 {
//model.Log.Debugf("getPopularCandidates, from roomVisitCount %s(%s) - %d", v.ImGroupId, v.Code, vc)
groups[v.ImGroupId] = &noPwdGroups[i]
visitCount[v.ImGroupId] = vc
}
} else {
// 如果没有,就从roomVisit中取
if vc, err := room_c.GetSetRoomVisitCount(v.ImGroupId); err == nil && vc > 0 {
model.Log.Infof("getPopularCandidates, from roomVisit %s(%s) - %d", v.ImGroupId, v.Code, vc)
groups[v.ImGroupId] = &noPwdGroups[i]
visitCount[v.ImGroupId] = vc
}
}
}
return groups, banCount, visitCount, nil
}
func GetVisitCount(groupIds []string) (map[string]int64, error) {
roomVisitCount, err := room_c.MGetRoomVisitCount(groupIds)
if err != nil {
return nil, err
}
visitCount := make(map[string]int64)
for _, v := range groupIds {
// 先从二级缓存中找
if c, ok := roomVisitCount[v]; ok {
if vc, err := strconv.ParseInt(c, 10, 64); err == nil && vc > 0 {
visitCount[v] = vc
}
} else {
// 如果没有,就从roomVisit中取
if vc, err := room_c.GetSetRoomVisitCount(v); err == nil && vc > 0 {
visitCount[v] = vc
}
}
}
return visitCount, nil
}
package group_r package group_r
import ( import (
"context"
"fmt" "fmt"
"git.hilo.cn/hilo-common/_const/rediskey"
"git.hilo.cn/hilo-common/domain" "git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext" "git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql" "git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/resource/redisCli"
"git.hilo.cn/hilo-common/rpc" "git.hilo.cn/hilo-common/rpc"
"git.hilo.cn/hilo-common/utils" "git.hilo.cn/hilo-common/utils"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
...@@ -18,7 +21,6 @@ import ( ...@@ -18,7 +21,6 @@ import (
"hilo-group/cv/user_cv" "hilo-group/cv/user_cv"
"hilo-group/domain/cache/group_c" "hilo-group/domain/cache/group_c"
"hilo-group/domain/cache/res_c" "hilo-group/domain/cache/res_c"
"hilo-group/domain/cache/room_c"
"hilo-group/domain/model/game_m" "hilo-group/domain/model/game_m"
"hilo-group/domain/model/group_m" "hilo-group/domain/model/group_m"
"hilo-group/domain/model/noble_m" "hilo-group/domain/model/noble_m"
...@@ -1251,7 +1253,7 @@ func GetGroupByCountry(c *gin.Context) (*mycontext.MyContext, error) { ...@@ -1251,7 +1253,7 @@ func GetGroupByCountry(c *gin.Context) (*mycontext.MyContext, error) {
//model.Log.Infof("GetGroupByCountry: page size = %d, page index = %d, banMap %v", pageSize, pageIndex, bannedGroups) //model.Log.Infof("GetGroupByCountry: page size = %d, page index = %d, banMap %v", pageSize, pageIndex, bannedGroups)
beginTime := time.Now() beginTime := time.Now()
groups, banCount, visitCount, err := getCandidatesByCountry(model, bannedGroups, countryShortName) groups, banCount, visitCount, err := group_s.GetCandidatesByCountry(model, bannedGroups, countryShortName)
if err != nil { if err != nil {
return myContext, err return myContext, err
} }
...@@ -1461,57 +1463,176 @@ func GetGroupByCountry(c *gin.Context) (*mycontext.MyContext, error) { ...@@ -1461,57 +1463,176 @@ func GetGroupByCountry(c *gin.Context) (*mycontext.MyContext, error) {
return myContext, nil return myContext, nil
} }
// 国家群候选:没有密码且没被封禁的群, 有国家 func GetGroupByCountryV2(c *gin.Context) (*mycontext.MyContext, error) {
func getCandidatesByCountry(model *domain.Model, bannedGroups map[string]uint64, country string) (map[string]*group_m.GroupInfo, int, map[string]int64, error) { myContext := mycontext.CreateMyContext(c.Keys)
noPwdGroups, err := group_m.FindOwnerCountryGroups(model, country) myUserId, err := req.GetUserId(c)
if err != nil { if err != nil {
return nil, 0, nil, err return myContext, err
} }
var groupIds []string
for _, v := range noPwdGroups { countryShortName := c.Query("countryShortName")
groupIds = append(groupIds, v.ImGroupId) // imGroupId if countryShortName == "" {
return myContext, myerr.NewSysError("countryShortName 为必填项")
} }
pageSize, err := strconv.Atoi(c.Query("pageSize"))
if err != nil || pageSize <= 0 {
pageSize = 10
}
pageIndex, err := strconv.Atoi(c.Query("pageIndex"))
if err != nil || pageIndex <= 0 {
pageIndex = 1
}
model := domain.CreateModelContext(myContext)
//roomVisitCount, err := room_c.GetAllRoomVisitCount() // 从redis分页取群组id
roomVisitCount, err := room_c.MGetRoomVisitCount(groupIds) sortedGroupIds := make([]string, 0, pageSize)
beginPos := int64(pageSize * (pageIndex - 1))
endPos := int64(pageSize*pageIndex - 1)
key := rediskey.GetGroupCountrySortList(countryShortName)
zList, err := redisCli.GetRedis().ZRangeWithScores(context.Background(), key, beginPos, endPos).Result()
if err != nil { if err != nil {
return nil, 0, nil, err model.Log.Errorf("GetGroupByCountry err:%v", err)
return myContext, err
}
for _, v := range zList {
sortedGroupIds = append(sortedGroupIds, v.Member.(string))
} }
gameRoom := group_m.GetGameGroupsMap(model)
banCount := 0 hotGroupList := make([]*group_m.GroupInfo, 0)
groups := make(map[string]*group_m.GroupInfo, 0) // * 同语言区 ^ 麦上有人 + 开放群 - 需要等级的群
visitCount := make(map[string]int64) for _, i := range sortedGroupIds {
for i, v := range noPwdGroups { gInfo, err := group_m.GetGroupInfo(model, i)
// 过滤掉被封禁的群 if err != nil {
if bannedGroups[v.ImGroupId] != 0 { model.Log.Errorf("GetGroupByCountry err:%v", err)
banCount++ return myContext, err
continue
}
// 过滤游戏房
if gameRoom[v.ImGroupId] {
continue
} }
hotGroupList = append(hotGroupList, gInfo)
}
total, err := redisCli.GetRedis().ZCard(context.Background(), key).Uint64()
if err != nil {
model.Log.Errorf("GetGroupByCountry err:%v", err)
return myContext, err
}
// 先从二级缓存中找 // 返回结果
if c, ok := roomVisitCount[v.ImGroupId]; ok { result := make([]group_cv.PopularGroupInfo, 0)
if vc, err := strconv.ParseInt(c, 10, 64); err == nil && vc > 0 {
//model.Log.Debugf("getPopularCandidates, from roomVisitCount %s(%s) - %d", v.ImGroupId, v.Code, vc)
groups[v.ImGroupId] = &noPwdGroups[i] groupIds := make([]string, 0)
visitCount[v.ImGroupId] = vc owners := make([]uint64, 0)
} for _, i := range hotGroupList {
} else { groupIds = append(groupIds, i.ImGroupId)
// 如果没有,就从roomVisit中取 owners = append(owners, i.Owner)
if vc, err := room_c.GetSetRoomVisitCount(v.ImGroupId); err == nil && vc > 0 { }
model.Log.Infof("getPopularCandidates, from roomVisit %s(%s) - %d", v.ImGroupId, v.Code, vc) powerIds, powerNames, powerNameplates, powerGrades, err := group_power_cv.BatchGetGroupPower(model.Db, owners)
if err != nil {
return myContext, err
}
groupMedals, err := group_m.BatchGetMedals(model.Db, groupIds)
if err != nil {
return myContext, err
}
resMedal, err := res_m.MedalGetAllMap(model.Db)
if err != nil {
return myContext, err
}
groups[v.ImGroupId] = &noPwdGroups[i] countryInfo, err := res_c.GetCountryIconMap(model)
visitCount[v.ImGroupId] = vc if err != nil {
return myContext, err
}
rr := rocket_m.RocketResult{}
maxStageMap, err := rr.GetMaxStage(model.DB(), groupIds)
if err != nil {
return myContext, err
}
roomCount, err := group_m.BatchGetRoomCount(model, groupIds)
if err != nil {
return nil, err
}
// 正在进行的游戏
games := game_m.GetNotEndGamesMap(model)
// 扶持等级
supportLevels, err := group_s.NewGroupService(myContext).GetWeekMaxSupportLevelMap()
if err != nil {
return myContext, err
}
visitCount, err := group_s.GetVisitCount(groupIds)
if err != nil {
model.Log.Errorf("GetGroupByCountry err:%v", err)
return myContext, err
}
for _, i := range hotGroupList {
var maxStage *uint16 = nil
if s, ok := maxStageMap[i.ImGroupId]; ok {
maxStage = &s
}
medals := make([]medal_cv.PicElement, 0)
if m, ok := groupMedals[i.ImGroupId]; ok {
for _, j := range m {
mId := uint32(j)
if e, ok := resMedal[mId]; ok {
medals = append(medals, medal_cv.PicElement{
PicUrl: e.PicUrl,
})
}
} }
} }
// 补上房间流水勋章
var pe *medal_cv.PicElement
_, pe, err = medal_cv.GetGroupConsumeMedal(model, i.ImGroupId)
if err != nil {
model.Log.Infof("GetGroupByCountry: GetGroupConsumeMedal: %s", err.Error())
} else if pe != nil {
medals = append(medals, medal_cv.PicElement{PicUrl: pe.PicUrl})
}
var password *string = nil
if len(i.Password) > 0 && i.Owner != myUserId {
emptyStr := ""
password = &emptyStr
}
result = append(result, group_cv.PopularGroupInfo{
GroupInfo: group_cv.GroupInfo{
GroupBasicInfo: group_cv.GroupBasicInfo{
GroupId: i.TxGroupId,
Name: i.Name,
Introduction: i.Introduction,
Notification: i.Notification,
FaceUrl: i.FaceUrl,
Code: i.Code,
CountryIcon: countryInfo[i.Country],
Password: password,
SupportLevel: supportLevels[i.ImGroupId],
GroupInUserDuration: visitCount[i.ImGroupId],
MicNumType: int(i.MicNumType),
GroupMedals: medals,
},
HasOnMic: micGroupNum[i.ImGroupId] > 0,
GroupPowerId: powerIds[i.Owner],
GroupPowerName: powerNames[i.Owner],
GroupPowerNameplate: powerNameplates[i.Owner],
GroupPower: group_cv.GroupPower{
Id: powerIds[i.Owner],
Name: powerNames[i.Owner],
Nameplate: powerNameplates[i.Owner],
Grade: powerGrades[i.Owner],
},
},
MicUsers: []user_cv.CvUserTiny{},
RoomUserCount: uint(roomCount[i.ImGroupId]),
MaxStage: maxStage,
GameTypes: games[i.TxGroupId],
})
} }
return groups, banCount, visitCount, nil
model.Log.Infof("GetGroupByCountry cost6:%v", time.Now().Sub(beginTime))
resp.ResponsePageOk(c, result, uint(total), pageIndex)
return myContext, nil
} }
// @Tags 资源 // @Tags 资源
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment