package group_r import ( "git.hilo.cn/hilo-common/domain" "git.hilo.cn/hilo-common/mycontext" "git.hilo.cn/hilo-common/resource/mysql" "github.com/gin-gonic/gin" "hilo-group/_const/enum/gift_e" "hilo-group/_const/enum/group_e" "hilo-group/cv/gift_cv" "hilo-group/cv/group_cv" "hilo-group/cv/group_power_cv" "hilo-group/cv/medal_cv" "hilo-group/cv/user_cv" "hilo-group/domain/cache/res_c" "hilo-group/domain/model/game_m" "hilo-group/domain/model/group_m" "hilo-group/domain/model/res_m" "hilo-group/domain/model/rocket_m" "hilo-group/domain/service/group_s" "hilo-group/req" "hilo-group/resp" "sort" "strconv" "time" ) // @Tags 群组 // @Summary 查询热门群组 // @Accept application/x-www-form-urlencoded // @Param token header string true "token" // @Param nonce header string true "随机数字" // @Param pageSize query int false "分页大小 默认:10" default(10) // @Param pageIndex query int false "第几个分页,从1开始 默认:1" default(1) // @Success 200 {object} cv.PopularGroupInfo // @Router /v1/imGroup/popular [get] func GetPopularGroups(c *gin.Context) (*mycontext.MyContext, error) { start := time.Now() myContext := mycontext.CreateMyContext(c.Keys) 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 } myUserId, _, _, _, myCountry, err := req.GetUserEx(c, myContext) if err != nil { return myContext, err } model := domain.CreateModelContext(myContext) /* 2022-06-30 老板说先不分区 regions, err := res_m.GetAllLangRegion(model) if err != nil { return myContext, err } myRegion := regions[myCountry] model.Log.Infof("GetPopularGroups: user %d, name = %s, country = %s, region = %s", myUserId, myNick, myCountry, myRegion) */ bannedGroups, err := group_m.GetBannedGroupsMap(model) if err != nil { return myContext, err } gs := group_m.GroupSetting{IsHidden: true} hiddenGroups, _ := gs.GetHidden(model.Db) if err != nil { return myContext, err } model.Log.Infof("GetPopularGroups: page size = %d, page index = %d, banMap %v, hidenMap %v,cost:%v", pageSize, pageIndex, bannedGroups, hiddenGroups, time.Now().Sub(start)) hotGroupList := make([]group_m.GroupInfo, 0) // 获取麦上有人的所有群组及麦上人数 v10,只有麦上有人的能上热门 micGroupNum, err := group_m.GetMicHasInGroupNum(model) if err != nil { return myContext, err } model.Log.Infof("GetMicHasInGroupNum: cost %v", time.Now().Sub(start)) banCount := 0 hiddenCount := 0 groupIds := make([]string, 0) for i := range micGroupNum { // 过滤掉被封禁的群 if bannedGroups[i] != 0 { banCount++ continue } // 过滤掉被隐藏的群 if _, exist := hiddenGroups[i]; exist { hiddenCount++ continue } groupIds = append(groupIds, i) } model.Log.Infof("GetPopularGroups, micGroupNum: %v, banned %d, hidden %d,cost:%v", micGroupNum, banCount, hiddenCount, time.Now().Sub(start)) // 3. 处理置顶群 topGroupIds, err := getTopGroups(model, bannedGroups, hiddenGroups) if err != nil { return myContext, err } sortedGroupIds := make([]string, 0) for _, i := range groupIds { found := false for _, j := range topGroupIds { if i == j { found = true break } } // 已经在置顶群范围内的跳过 if !found { sortedGroupIds = append(sortedGroupIds, i) } } groupIds = append(groupIds, topGroupIds...) groups, err := group_m.BatchGetGroupInfo(model, groupIds) if err != nil { return myContext, err } for _, i := range topGroupIds { /* 2022-06-30 老板说先不分区 // 置顶只对同语言区的生效 if myRegion != regions[topGroupInfo[i].Country] { continue } */ // 已经置顶的,直接进队列,不再参与排序 hotGroupList = append(hotGroupList, groups[i]) //delete(groupIds, i) } // for pretty log //logstr := "" //for _, i := range hotGroupList { //logstr += " " + i.ImGroupId //} //logstr += " |" countryScore := make(map[string]int) if len(myCountry) > 0 { for _, i := range sortedGroupIds { if myCountry == groups[i].Country { countryScore[i] = 1 } else { countryScore[i] = 0 } } } model.Log.Infof("GetPopularGroups, countryScore[*]: %v,cost:%v", countryScore, time.Now().Sub(start)) now := time.Now() bTime := now.Add(-time.Minute * 30) g := gift_cv.GiftOperate{SceneType: gift_e.GroupSceneType} diamonds, err := g.GetRangeConsumeSummaryV2(bTime, now, groupIds) if err != nil { return myContext, err } model.Log.Infof("GetPopularGroups, diamonds in 30 mins: %v,cost:%v", diamonds, time.Now().Sub(start)) visitCount, err := group_m.BatchGetRoomVisitCount(model.Log, groupIds) if err != nil { return myContext, err } // 排序优先级2022-07-25版本 sort.Slice(sortedGroupIds, func(i, j int) bool { gi := sortedGroupIds[i] gj := sortedGroupIds[j] // 1、老板说,优化按国家 if countryScore[gi] > countryScore[gj] { return true } else if countryScore[gi] < countryScore[gj] { return false } // 2、按麦上人数多少排序 if micGroupNum[gi] > micGroupNum[gj] { return true } else if micGroupNum[gi] < micGroupNum[gj] { return false } // 3、麦上人数相同,按30分钟内送礼钻石数排序 if diamonds[gi] > diamonds[gj] { return true } else if diamonds[gi] < diamonds[gj] { return false } // 4、按热度递减排序 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 }) // for pretty log // * 同国家 ^ 麦上有人 + 开放群 - 需要等级的群 for _, g := range sortedGroupIds { hotGroupList = append(hotGroupList, groups[g]) //prefix := " " //if countryScore[g] == 0 { //prefix += "*" //} //logstr += prefix + g + ":" + groups[g].Code + ":" + strconv.Itoa(int(micGroupNum[g])) + // ":" + strconv.FormatUint(diamonds[g], 10) + ":" + strconv.Itoa(int(visitCount[g])) } total := len(hotGroupList) model.Log.Infof("GetPopularGroups: hotGroupList size = %d,cost:%v", total, time.Now().Sub(start)) result := make([]group_cv.PopularGroupInfo, 0) beginPos := pageSize * (pageIndex - 1) endPos := pageSize * pageIndex if beginPos < total { if endPos > total { endPos = total } groupIds := make([]string, 0) owners := make([]uint64, 0) for _, i := range hotGroupList[beginPos:endPos] { groupIds = append(groupIds, i.ImGroupId) owners = append(owners, i.Owner) } powerIds, powerNames, 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 } //roomMicUserMap, err := group_m.BatchGetAllMicUser(model, groupIds) //if err != nil { // return myContext, err //} model.Log.Infof("GetPopularGroups: final start = %d, end = %d, groupIds %v,cost:%v", beginPos, endPos, groupIds, time.Now().Sub(start)) roomCount, err := group_m.BatchGetRoomCount(model, groupIds) if err != nil { return nil, err } countryInfo, err := res_c.GetCountryIconMap(model) if err != nil { return myContext, err } supportLevels, err := group_s.NewGroupService(myContext).GetWeekMaxSupportLevelMap() if err != nil { return myContext, err } rr := rocket_m.RocketResult{} maxStageMap, err := rr.GetMaxStage(mysql.Db, groupIds) if err != nil { return myContext, err } // 正在进行的游戏 games := game_m.GetNotEndGamesMap(model) for _, i := range hotGroupList[beginPos:endPos] { micUsers := make([]user_cv.CvUserTiny, 0) 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("GetPopularGroups: 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: true, GroupPowerId: powerIds[i.Owner], GroupPowerName: powerNames[i.Owner], }, MicUsers: micUsers, RoomUserCount: uint(roomCount[i.ImGroupId]), MaxStage: maxStage, GameTypes: games[i.TxGroupId], }) } } resp.ResponsePageOk(c, result, uint(total), pageIndex) return myContext, nil } func getTopGroups(model *domain.Model, bannedGroups map[string]uint64, hiddenGroups map[string]struct{}) ([]string, error) { topGroups, err := group_m.GroupTopGetAll(model) if err != nil { return nil, err } result := make([]string, 0) for _, i := range topGroups { // 过滤掉被封禁的群。理论上是不需要的,因为被封禁的不会被置顶。这里只是为了保险 if bannedGroups[i] != 0 { continue } // 过滤掉被隐藏的群 if _, exist := hiddenGroups[i]; exist { continue } result = append(result, i) } return result, nil } type GetLatestGroupsReq struct { PageSize int `form:"pageSize"` // binding:"min=1" PageIndex int `form:"pageIndex"` LastId int `form:"lastId"` } // @Tags 群组 // @Summary 查询最新群组 // @Accept application/x-www-form-urlencoded // @Param token header string true "token" // @Param nonce header string true "随机数字" // @Param pageSize query int false "分页大小 默认:10" default(10) // @Param pageIndex query int false "第几个分页,从1开始 默认:1" default(1) // @Param lastId query int false "上一页列表的最后一个id,避免分页重复 默认:0" default(1) // @Success 200 {object} cv.LatestGroupInfo // @Router /v1/imGroup/latest [get] func GetLatestGroups(c *gin.Context) (*mycontext.MyContext, error) { myContext := mycontext.CreateMyContext(c.Keys) request := &GetLatestGroupsReq{} err := c.ShouldBindQuery(request) if err != nil { return myContext, err } if request.PageSize <= 0 { request.PageSize = 10 } if request.PageIndex <= 0 { request.PageIndex = 1 } // 上一页最后一个id, 避免分页变化数据重复 if request.LastId <= 0 { request.LastId = 0 } //offset := (req.PageIndex - 1) * req.PageSize model := domain.CreateModelContext(myContext) micGroupNum, err := group_m.GetMicHasInGroupNum(model) if err != nil { return myContext, err } gids := make([]string, 0) for i, _ := range micGroupNum { gids = append(gids, i) } // 获取最新群组列表 groupInfos, err := group_m.GetLatestGroupInfos(model, request.PageSize, request.LastId, gids) if err != nil { return myContext, err } // 提取id groupIds := make([]string, 0, len(groupInfos)) for _, group := range groupInfos { groupIds = append(groupIds, group.ImGroupId) } // 获取国家信息 countryInfo, err := res_c.GetCountryIconMap(model) if err != nil { return myContext, err } // 获取本周最高的扶持等级 supportLevels, err := group_s.NewGroupService(myContext).GetWeekMaxSupportLevelMap() if err != nil { return myContext, err } // 用户id myUserId, err := req.GetUserId(c) if err != nil { return myContext, err } // 获取房间浏览数量 visitCount, err := group_m.BatchGetRoomVisitCount(model.Log, groupIds) if err != nil { return myContext, err } // 获取群势力信息 owners := make([]uint64, 0) for _, group := range groupInfos { owners = append(owners, group.Owner) } powerIds, powerNames, 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 } // 获取房间人数信息 roomCount, err := group_m.BatchGetRoomCount(model, groupIds) if err != nil { return nil, err } // 获取火箭信息 rr := rocket_m.RocketResult{} maxStageMap, err := rr.GetMaxStage(mysql.Db, groupIds) if err != nil { return myContext, err } // 正在进行的游戏 games := game_m.GetNotEndGamesMap(model) result := make([]*group_cv.LatestGroupInfo, 0) for _, group := range groupInfos { micUsers := make([]user_cv.CvUserTiny, 0) // 密码应该是一直为空? var password *string = nil if len(group.Password) > 0 && group.Owner != myUserId { emptyStr := "" password = &emptyStr } // 勋章信息 medals := make([]medal_cv.PicElement, 0) if m, ok := groupMedals[group.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, group.ImGroupId) if err != nil { model.Log.Infof("GetLatestGroups: GetGroupConsumeMedal: %s", err.Error()) } else if pe != nil { medals = append(medals, medal_cv.PicElement{PicUrl: pe.PicUrl}) } // 最大的火箭 var maxStage *uint16 = nil if s, ok := maxStageMap[group.ImGroupId]; ok { maxStage = &s } result = append(result, &group_cv.LatestGroupInfo{ GroupInfo: group_cv.GroupInfo{ GroupBasicInfo: group_cv.GroupBasicInfo{ Id: group.Id, GroupId: group.TxGroupId, Name: group.Name, Introduction: group.Introduction, Notification: group.Notification, FaceUrl: group.FaceUrl, Code: group.Code, CountryIcon: countryInfo[group.Country], Password: password, SupportLevel: supportLevels[group.ImGroupId], GroupInUserDuration: visitCount[group.ImGroupId], MicNumType: int(group.MicNumType), GroupMedals: medals, }, HasOnMic: true, GroupPowerId: powerIds[group.Owner], GroupPowerName: powerNames[group.Owner], }, MicUsers: micUsers, RoomUserCount: uint(roomCount[group.ImGroupId]), MaxStage: maxStage, GameTypes: games[group.TxGroupId], }) } resp.ResponseOk(c, result) return myContext, nil } // @Tags 群组 // @Summary 查询推荐的群组(version>=2.19) // @Accept application/x-www-form-urlencoded // @Param token header string true "token" // @Param nonce header string true "随机数字" // @Success 200 {object} cv.PopularGroupInfo // @Router /v1/imGroup/recommended [get] func GetRecommendGroup(c *gin.Context) (*mycontext.MyContext, error) { myContext := mycontext.CreateMyContext(c.Keys) model := domain.CreateModelContext(myContext) bannedGroups, err := group_m.GetBannedGroupsMap(model) if err != nil { return myContext, err } //noPwdGroups, err := group_m.FindNoPasswordGroups(model) //if err != nil { // return myContext, err //} // 获取麦上有人的所有群组及麦上人数 micGroupNum, err := group_m.GetMicHasInGroupNum(model) if err != nil { return myContext, err } var micGroupIds []string for groupId := range micGroupNum { micGroupIds = append(micGroupIds, groupId) } model.Log.Infof("GetRecommendGroups, micGroupNum : %v", micGroupNum) noPwdGroups, err := group_m.FindNoPasswordGroupsV2(model, micGroupIds) if err != nil { return myContext, err } model.Log.Infof("GetRecommendGroups: noPwdGroups = %d, bannedGroups = %d", len(noPwdGroups), len(bannedGroups)) groupIds := make([]string, 0) banCount := 0 for _, v := range noPwdGroups { if _, ok := micGroupNum[v.ImGroupId]; ok { if bannedGroups[v.ImGroupId] != 0 { banCount++ } else { groupIds = append(groupIds, v.ImGroupId) } } } model.Log.Infof("GetRecommendGroups: size = %d, banned %d", len(groupIds), banCount) myService := domain.CreateService(myContext) result, _, err := group_cv.BuildJoinedGroupInfo(myService, 0, groupIds, group_e.GROUP_RECOMMEND_SIZE, 1) if err != nil { return myContext, err } resp.ResponseOk(c, result) return myContext, nil }