1280 lines
45 KiB
Go
1280 lines
45 KiB
Go
package v1
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
"fmt"
|
||
"net/url"
|
||
"reflect"
|
||
"strconv"
|
||
"sync/atomic"
|
||
"time"
|
||
|
||
v1indexpb "go-common/app/interface/live/app-interface/api/http/v1"
|
||
"go-common/app/interface/live/app-interface/conf"
|
||
"go-common/app/interface/live/app-interface/dao"
|
||
liveuserV1 "go-common/app/service/live/live_user/api/liverpc/v1"
|
||
relationV2 "go-common/app/service/live/relation/api/liverpc/v2"
|
||
roomV1 "go-common/app/service/live/room/api/liverpc/v1"
|
||
roomV2 "go-common/app/service/live/room/api/liverpc/v2"
|
||
bannerV1 "go-common/app/service/live/room_ex/api/liverpc/v1"
|
||
"go-common/app/service/live/third_api/bvc"
|
||
userextV1 "go-common/app/service/live/userext/api/liverpc/v1"
|
||
"go-common/library/ecode"
|
||
"go-common/library/log"
|
||
"go-common/library/net/metadata"
|
||
"go-common/library/net/rpc/liverpc"
|
||
rpcCtx "go-common/library/net/rpc/liverpc/context"
|
||
"go-common/library/sync/errgroup"
|
||
"go-common/library/xstr"
|
||
|
||
"math/rand"
|
||
|
||
"github.com/bitly/go-simplejson"
|
||
"github.com/pkg/errors"
|
||
|
||
"go-common/library/net/http/blademaster"
|
||
)
|
||
|
||
const (
|
||
_bannerType = 1
|
||
_navigatorType = 2
|
||
_yunyingRecFormType = 3
|
||
_yunyingRecSquareType = 4
|
||
_recFormType = 6
|
||
_recSquareType = 7
|
||
_feedType = 8
|
||
_parentAreaFormType = 9
|
||
_parentAreaSquareType = 10
|
||
_myAreaTagType = 12
|
||
_seaPatrolType = 14
|
||
_myAreaTagListType = 13
|
||
_activityType = 11
|
||
|
||
// _recTypeOnline = 1
|
||
// _recTypeIncome = 2
|
||
_recTypeForce = 3
|
||
_recTypeSkyHorse = 4
|
||
|
||
_defaultRecNum = 24
|
||
|
||
_skyHorseRecTimeOut = 100
|
||
|
||
_areaModuleLink = "https://live.bilibili.com/app/area?parent_area_id=%d&parent_area_name=%s&area_id=%d&area_name=%s"
|
||
|
||
_activityGo = 0
|
||
_activityBook = 1
|
||
_activityUnbook = 2
|
||
|
||
_mobileIndexBadgeColorDefault = "#FB9E60"
|
||
)
|
||
|
||
// Service struct
|
||
type Service struct {
|
||
conf *conf.Config
|
||
// optionally add other properties here, such as dao
|
||
dao *dao.Dao
|
||
allListInfo atomic.Value
|
||
}
|
||
|
||
type roomItem struct {
|
||
RoomId int64 `json:"roomid"`
|
||
Title string `json:"title"`
|
||
Uname string `json:"uname"`
|
||
Online int64 `json:"online"`
|
||
Cover string `json:"cover"`
|
||
Link string `json:"link"`
|
||
Face string `json:"face"`
|
||
AreaV2ParentId int64 `json:"area_v2_parent_id"`
|
||
AreaV2ParentName string `json:"area_v2_parent_name"`
|
||
AreaV2Id int64 `json:"area_v2_id"`
|
||
AreaV2Name string `json:"area_v2_name"`
|
||
PlayUrl string `json:"play_url"`
|
||
PlayUrlH265 string `json:"play_url_h265"`
|
||
CurrentQuality int64 `json:"current_quality"`
|
||
BroadcastType int64 `json:"broadcast_type"`
|
||
PendentRu string `json:"pendent_ru"`
|
||
PendentRuPic string `json:"pendent_ru_pic"`
|
||
PendentRuColor string `json:"pendent_ru_color"`
|
||
RecType int64 `json:"rec_type"`
|
||
PkId int64 `json:"pk_id"`
|
||
AcceptQuality []int64 `json:"accept_quality"`
|
||
}
|
||
|
||
type offlineItem struct {
|
||
Id int `json:"id"`
|
||
Name string `json:"name"`
|
||
}
|
||
|
||
type userTagItem struct {
|
||
AreaV2Id int `json:"area_v2_id"`
|
||
AreaV2Name string `json:"area_v2_name"`
|
||
AreaV2ParentId int `json:"area_v2_parent_id"`
|
||
AreaV2ParentName string `json:"area_v2_parent_name"`
|
||
Pic string `json:"pic"`
|
||
Link string `json:"link"`
|
||
IsAdvice int `json:"is_advice"`
|
||
}
|
||
|
||
type commonResp struct {
|
||
ModuleInfo map[string]interface{}
|
||
ExtraInfo map[string]interface{}
|
||
List interface{}
|
||
}
|
||
|
||
type ModuleResp struct {
|
||
Interval int `json:"interval"`
|
||
ModuleList []map[string]interface{} `json:"module_list"`
|
||
}
|
||
|
||
// New init
|
||
func New(c *conf.Config) (s *Service) {
|
||
s = &Service{
|
||
conf: c,
|
||
dao: dao.New(c),
|
||
}
|
||
go s.tickCacheAllList(context.TODO())
|
||
return s
|
||
}
|
||
|
||
// GetAllList implementation
|
||
// 首页大接口
|
||
func (s *Service) GetAllList(ctx context.Context, req *v1indexpb.GetAllListReq) (ret interface{}, err error) {
|
||
resp := &ModuleResp{
|
||
Interval: 10,
|
||
}
|
||
build := req.Build
|
||
relationTimeout := conf.GetTimeout("relation", 200)
|
||
// dao.LiveUserApi.V1UserSetting.GetTag(ctx, &liveuserV1.UserSettingGetTagReq{})
|
||
midInterface, isUIDSet := metadata.Value(ctx, metadata.Mid).(int64) // 大多使用header里的mid解析, 框架已封装请求的header
|
||
isSkyHorseGray := false
|
||
mid := int64(0)
|
||
if isUIDSet {
|
||
mid = midInterface
|
||
// 天马灰度
|
||
isSkyHorseGray = s.isSkyHorseRec(mid)
|
||
}
|
||
|
||
buvid := ""
|
||
// 主站封好的,可从device里获取到sid、buvid、buvid3、build、channel、device、mobi_app、platform
|
||
device, ok := metadata.Value(ctx, metadata.Device).(*blademaster.Device)
|
||
if ok {
|
||
buvid = device.Buvid
|
||
}
|
||
// deviceInterface := req.Device
|
||
// device := deviceInterface.(*bm.Device)
|
||
if req.Platform == "" || req.Device == "" || req.Scale == "" || req.RelationPage == 0 {
|
||
err = errors.WithMessage(ecode.InvalidParam, "INVALID PARAM")
|
||
return
|
||
}
|
||
|
||
allListTimeout := time.Duration(conf.GetTimeout("allList", 50)) * time.Millisecond
|
||
rawModuleList := s.getAllListFromCache(rpcCtx.WithTimeout(ctx, allListTimeout))
|
||
|
||
if rawModuleList == nil {
|
||
err = errors.WithMessage(ecode.GetAllListReturnError, "")
|
||
return
|
||
}
|
||
|
||
// 大分区常量定义
|
||
parentName := map[int64]string{
|
||
1: "娱乐",
|
||
2: "游戏",
|
||
3: "手游",
|
||
4: "绘画",
|
||
5: "电台",
|
||
}
|
||
|
||
// 天马灰度/保底
|
||
defaultRecSlice := make([]map[string]interface{}, 0)
|
||
loginRecRoomIDSlice := make([]int64, 0)
|
||
// [{module_info:{},list:{}}...]
|
||
resp.ModuleList = make([]map[string]interface{}, len(rawModuleList))
|
||
for _, m := range rawModuleList {
|
||
module := m.(map[string]interface{})
|
||
if module["module_info"] == nil {
|
||
log.Error("empty_module_info:%+v \n", m)
|
||
fmt.Printf("empty_module_info:raw_all:%+v \n", rawModuleList)
|
||
}
|
||
moduleInfo := module["module_info"].(map[string]interface{})
|
||
moduleType := jsonMustInt(moduleInfo["type"], 0)
|
||
if moduleType == 0 {
|
||
continue
|
||
}
|
||
list := module["list"].([]interface{})
|
||
if moduleType == _recFormType || moduleType == _recSquareType {
|
||
for _, r := range list {
|
||
recItem := r.(map[string]interface{})
|
||
defaultRecSlice = append(defaultRecSlice, recItem)
|
||
roomID := jsonMustInt(recItem["roomid"], 0)
|
||
if roomID == 0 {
|
||
continue
|
||
}
|
||
// 登录了也有可能请求不到数据,登录的保底用
|
||
loginRecRoomIDSlice = append(loginRecRoomIDSlice, roomID)
|
||
}
|
||
}
|
||
}
|
||
// 常用标签 roomListMap
|
||
myTagRoomListMap := make(map[int64][]*roomV2.AppIndexGetMultiRoomListResp_RoomList)
|
||
myTagAreaIds := make([]int64, 0, 4)
|
||
myTagAreaInfoMap := make(map[int64]*liveuserV1.UserSettingGetTagResp_Tags)
|
||
|
||
myTagResp := commonResp{
|
||
List: make([]interface{}, 0),
|
||
}
|
||
attentionResp := commonResp{
|
||
List: make([]interface{}, 0),
|
||
}
|
||
loginRecResp := commonResp{}
|
||
seaResp := commonResp{}
|
||
bannerResp := commonResp{
|
||
List: make([]interface{}, 0),
|
||
}
|
||
// playurl定义
|
||
attentionRoomListPlayURLMap := make(map[int64]*bvc.PlayUrlItem)
|
||
loginRecRoomListPlayURLMap := make(map[int64]*bvc.PlayUrlItem)
|
||
myTagRoomListPlayURLMap := make(map[int64]*bvc.PlayUrlItem)
|
||
otherRoomListPlayURLMap := make(map[int64]*bvc.PlayUrlItem)
|
||
otherRoomIDSlice := make([]int64, 0)
|
||
|
||
isSkyHorseGrayOk := 0
|
||
|
||
// 此group包含首页的一些任务
|
||
// 但是任务之间不能同时cancel
|
||
// 不然一个接口出错所有任务都cancel首页就空了
|
||
// 所以return固定为nil(一个wg的任务使用的是从bm context继承来的ctx,cancel后一起推出)
|
||
// 只有上层ctx(http的ctx)出问题(超时等)才会退出后续任务1
|
||
wg, _ := errgroup.WithContext(ctx)
|
||
for _, m := range rawModuleList {
|
||
// {module_info:xx}
|
||
module := m.(map[string]interface{})
|
||
// {id:xx,type:xx,pic:xx,title:xx,link:xx,...}
|
||
moduleInfo := module["module_info"].(map[string]interface{})
|
||
moduleList := module["list"].([]interface{})
|
||
moduleType := jsonMustInt(moduleInfo["type"], 0)
|
||
if moduleType == 0 {
|
||
continue
|
||
}
|
||
// banner分支 分端分版本
|
||
if moduleType == _bannerType {
|
||
bannerTimeout := time.Duration(conf.GetTimeout("banner", 100)) * time.Millisecond
|
||
wg.Go(func() error {
|
||
bannerList, bannerErr := dao.RoomExtApi.V1Banner.GetNewBanner(rpcCtx.WithTimeout(ctx, time.Duration(bannerTimeout)*time.Millisecond), &bannerV1.BannerGetNewBannerReq{UserPlatform: req.Platform, Build: build, UserDevice: req.Device})
|
||
if bannerErr != nil {
|
||
log.Error("[GetAllList]get banner rpc error, roomex.v1.Banner.GetNewBanner, error:%+v,rpctimeout:%d", bannerErr, bannerTimeout)
|
||
return nil
|
||
}
|
||
if bannerList.Code != 0 || bannerList.Data == nil {
|
||
log.Error("[GetAllList]get banner response error, code, %d, msg: %s, error:%+v", bannerList.Code, bannerList.Msg, bannerErr)
|
||
return nil
|
||
}
|
||
if len(bannerList.Data) > 0 {
|
||
for _, bannerInfo := range bannerList.Data {
|
||
bannerResp.List = append(bannerResp.List.([]interface{}), map[string]interface{}{
|
||
"id": bannerInfo.Id,
|
||
"pic": bannerInfo.Pic,
|
||
"link": bannerInfo.Link,
|
||
"title": bannerInfo.Title,
|
||
})
|
||
}
|
||
}
|
||
return nil
|
||
})
|
||
}
|
||
// 关注分支
|
||
if moduleType == _feedType {
|
||
if !isUIDSet {
|
||
continue
|
||
}
|
||
wg.Go(func() error {
|
||
currentAttentionRoomMap := make(map[int64]bool)
|
||
currentAttentionRoomSlice := make([]int64, 0)
|
||
attentionResp.ModuleInfo = moduleInfo
|
||
currentAttention, attentionErr := dao.RelationApi.V2App.LiveHomePage(rpcCtx.WithTimeout(ctx, time.Duration(relationTimeout)*time.Millisecond), &relationV2.AppLiveHomePageReq{RelationPage: req.RelationPage})
|
||
if attentionErr != nil {
|
||
log.Error("[GetAllList]get user attention rpc error, relation.v2.App.liveHomePage, error:%+v,rpctimeout:%d", attentionErr, relationTimeout)
|
||
} else if currentAttention.Code != 0 || currentAttention.Data == nil {
|
||
log.Error("[GetAllList]get user attention response error, code, %d, msg: %s, error:%+v", currentAttention.Code, currentAttention.Msg, attentionErr)
|
||
} else {
|
||
attentionResp.ExtraInfo = map[string]interface{}{
|
||
"total_count": currentAttention.Data.TotalCount,
|
||
"time_desc": currentAttention.Data.TimeDesc,
|
||
"uname_desc": currentAttention.Data.UnameDesc,
|
||
"tags_desc": currentAttention.Data.TagsDesc,
|
||
"relation_page": currentAttention.Data.RelationPage,
|
||
}
|
||
// 存关注map
|
||
for _, attentionCard := range currentAttention.Data.Rooms {
|
||
currentAttentionRoomMap[attentionCard.Roomid] = true
|
||
currentAttentionRoomSlice = append(currentAttentionRoomSlice, attentionCard.Roomid)
|
||
attentionResp.List = append(attentionResp.List.([]interface{}), attentionCard)
|
||
}
|
||
// playurl
|
||
attentionRoomListPlayURLMap = dao.BvcApi.GetPlayUrlMulti(ctx, currentAttentionRoomSlice, 0, 4, build, req.Platform)
|
||
}
|
||
useDefaultRec := false
|
||
isOpen := conf.Conf.SkyHorseStatus
|
||
if isOpen && isSkyHorseGray {
|
||
// 取天马数据,传入关注当前刷列表roomid+强推,天马会对传入的roomid去重
|
||
// duplicates := append(currentAttentionRoomSlice, forceRecSlice...)
|
||
// getSkyHorseRoomList已经对强推去重
|
||
duplicates := currentAttentionRoomSlice
|
||
skyRecResult, skyHorseErr := getSkyHorseRoomList(ctx, mid, buvid, req.Build, req.Platform, duplicates, 1)
|
||
if skyHorseErr != nil {
|
||
log.Warn("[GetAllList]get data from skyHorse err: %v", skyHorseErr)
|
||
useDefaultRec = true
|
||
}
|
||
if skyRecResult == nil {
|
||
log.Warn("[GetAllList]get data from skyHorse empty: %v", skyHorseErr)
|
||
useDefaultRec = true
|
||
}
|
||
if len(skyRecResult) < 6 {
|
||
log.Warn("[GetAllList]get data from skyHorse not enough: %v", skyRecResult)
|
||
useDefaultRec = true
|
||
}
|
||
skyRecResultInterface := make([]map[string]interface{}, 0)
|
||
for _, item := range skyRecResult {
|
||
loginRecRoomIDSlice = append(loginRecRoomIDSlice, item.RoomId)
|
||
skyRecResultInterface = append(skyRecResultInterface, map[string]interface{}{
|
||
"roomid": item.RoomId,
|
||
"title": item.Title,
|
||
"uname": item.Uname,
|
||
"online": item.Online,
|
||
"cover": item.Cover,
|
||
"link": item.Link,
|
||
"face": item.Face,
|
||
"area_v2_parent_id": item.AreaV2ParentId,
|
||
"area_v2_parent_name": item.AreaV2ParentName,
|
||
"area_v2_id": item.AreaV2Id,
|
||
"area_v2_name": item.AreaV2Name,
|
||
"play_url": item.PlayUrl,
|
||
"current_quality": item.CurrentQuality,
|
||
"broadcast_type": item.BroadcastType,
|
||
"pendent_ru": item.PendentRu,
|
||
"pendent_ru_pic": item.PendentRuPic,
|
||
"pendent_ru_color": item.PendentRuColor,
|
||
"rec_type": item.RecType,
|
||
"pk_id": item.PkId,
|
||
"accept_quality": item.AcceptQuality,
|
||
})
|
||
}
|
||
loginRecResp.List = skyRecResultInterface
|
||
isSkyHorseGrayOk = 1
|
||
}
|
||
// 保底逻辑
|
||
if !isOpen || !isSkyHorseGray || useDefaultRec {
|
||
newDefaultRecSlice := make([]map[string]interface{}, 0)
|
||
for _, defaultRecRoom := range defaultRecSlice {
|
||
roomID := jsonMustInt(defaultRecRoom["roomid"], 0)
|
||
if roomID == 0 {
|
||
continue
|
||
}
|
||
if _, exist := currentAttentionRoomMap[roomID]; !exist {
|
||
// 天马没取到保底:默认推荐要对关注当前刷去重
|
||
newDefaultRecSlice = append(newDefaultRecSlice, defaultRecRoom)
|
||
}
|
||
}
|
||
// 只返24个
|
||
if len(newDefaultRecSlice) > _defaultRecNum {
|
||
loginRecResp.List = newDefaultRecSlice[:_defaultRecNum]
|
||
} else {
|
||
loginRecResp.List = newDefaultRecSlice
|
||
}
|
||
isSkyHorseGrayOk = 0
|
||
}
|
||
loginRecRoomListPlayURLMap = dao.BvcApi.GetPlayUrlMulti(ctx, loginRecRoomIDSlice, 0, 4, build, req.Platform)
|
||
return nil
|
||
})
|
||
}
|
||
|
||
// 常用标签分支
|
||
if moduleType == _myAreaTagType {
|
||
wg.Go(func() error {
|
||
myTagResp.ModuleInfo = moduleInfo
|
||
getMyTagTimeout := time.Duration(conf.GetTimeout("getMyTag", 100)) * time.Millisecond
|
||
myTagListResp, userTagError := dao.LiveUserApi.V1UserSetting.GetTag(rpcCtx.WithTimeout(ctx, getMyTagTimeout), &liveuserV1.UserSettingGetTagReq{})
|
||
if userTagError != nil {
|
||
log.Error("[GetAllList]get user tag rpc error, live_user.v1.usersetting.get_tag, error:%+v", userTagError)
|
||
return nil // 如果return err 则所有当前group的任务都会cancel
|
||
}
|
||
|
||
if myTagListResp.Code != 0 || myTagListResp.Data == nil {
|
||
log.Error("[GetAllList]get user tag return error, code, %d, msg: %s, error:%+v", myTagListResp.Code, myTagListResp.Msg, userTagError)
|
||
return nil
|
||
}
|
||
if myTagListResp.Data != nil {
|
||
myTagResp.ExtraInfo = make(map[string]interface{})
|
||
myTagResp.ExtraInfo["is_gray"] = myTagListResp.Data.IsGray
|
||
myTagResp.ExtraInfo["offline"] = make([]interface{}, 0)
|
||
for _, offlineInfo := range myTagListResp.Data.Offline {
|
||
myTagResp.ExtraInfo["offline"] = append(myTagResp.ExtraInfo["offline"].([]interface{}), &offlineItem{Id: int(offlineInfo.Id), Name: offlineInfo.Name})
|
||
}
|
||
}
|
||
|
||
for _, tagInfo := range myTagListResp.Data.Tags {
|
||
myTagAreaIds = append(myTagAreaIds, tagInfo.Id)
|
||
myTagAreaInfoMap[tagInfo.Id] = tagInfo
|
||
link := fmt.Sprintf("http://live.bilibili.com/app/area?parent_area_id=%d&parent_area_name=%s&area_id=%d&area_name=%s", tagInfo.ParentId, parentName[tagInfo.ParentId], tagInfo.Id, tagInfo.Name)
|
||
myTagResp.List = append(myTagResp.List.([]interface{}), &userTagItem{AreaV2Id: int(tagInfo.Id), AreaV2Name: tagInfo.Name, AreaV2ParentId: int(tagInfo.ParentId), AreaV2ParentName: parentName[tagInfo.ParentId], Link: link, Pic: tagInfo.Pic, IsAdvice: int(tagInfo.IsAdvice)})
|
||
}
|
||
if (req.Platform == "ios" && build > 8220) || (req.Platform == "android" && build > 5333002) {
|
||
myTagResp.List = append(myTagResp.List.([]interface{}), &userTagItem{AreaV2Id: int(0), AreaV2Name: "全部标签", AreaV2ParentId: int(0), AreaV2ParentName: "", Pic: "http://i0.hdslb.com/bfs/vc/ff03528785fc8c91491d79e440398484811d6d87.png", Link: "http://live.bilibili.com/app/mytag/", IsAdvice: 1})
|
||
}
|
||
if len(myTagAreaIds) <= 0 {
|
||
log.Error("[GetAllList]get user tag return empty!uid:%d", mid)
|
||
return nil
|
||
}
|
||
// 常用标签房间列表 先生成最后wait替换就好了
|
||
getMultiRoomListTimeout := time.Duration(conf.GetTimeout("getMultiRoomList", 100)) * time.Millisecond
|
||
myTagRoomListResp, multiRoomListErr := dao.RoomApi.V2AppIndex.GetMultiRoomList(rpcCtx.WithTimeout(ctx, getMultiRoomListTimeout), &roomV2.AppIndexGetMultiRoomListReq{AreaIds: xstr.JoinInts(myTagAreaIds), Platform: req.Platform})
|
||
|
||
if multiRoomListErr != nil {
|
||
log.Error("[GetAllList]get multi list rpc error, room.v2.AppIndex.GetMultiRoomList, error:%+v", multiRoomListErr)
|
||
return nil
|
||
}
|
||
if myTagRoomListResp.Code != 0 || myTagRoomListResp.Data == nil {
|
||
log.Error("[GetAllList]get multi list response error, code, %d, msg: %s, error:%+v", myTagRoomListResp.Code, myTagRoomListResp.Msg, multiRoomListErr)
|
||
return nil
|
||
}
|
||
// 保存roomListMap,wait 聚合数据
|
||
myTagRoomIDSlice := make([]int64, 0)
|
||
for _, myTagRoomItem := range myTagRoomListResp.Data {
|
||
myTagRoomListMap[myTagRoomItem.Id] = myTagRoomItem.List
|
||
for _, item := range myTagRoomItem.List {
|
||
myTagRoomIDSlice = append(myTagRoomIDSlice, item.Roomid)
|
||
}
|
||
}
|
||
myTagRoomListPlayURLMap = dao.BvcApi.GetPlayUrlMulti(ctx, myTagRoomIDSlice, 0, 4, build, req.Platform)
|
||
|
||
return nil
|
||
})
|
||
}
|
||
|
||
if moduleType == _seaPatrolType {
|
||
seaPatrolList := make([]interface{}, 0)
|
||
if !isUIDSet {
|
||
continue
|
||
}
|
||
// 大航海分支
|
||
wg.Go(func() error {
|
||
seaPatrolTimeout := time.Duration(conf.GetTimeout("seaPatrol", 100)) * time.Millisecond
|
||
seaPatrol, seaPatrolError := dao.LiveUserApi.V1Note.Get(rpcCtx.WithTimeout(ctx, seaPatrolTimeout), &liveuserV1.NoteGetReq{})
|
||
if seaPatrolError != nil {
|
||
log.Error("[GetAllList]get sea patrol rpc error, liveuser.v1.Note.Get, error:%+v", seaPatrolError)
|
||
return nil
|
||
}
|
||
if seaPatrol.Code != 0 || seaPatrol.Data == nil {
|
||
log.Error("[GetAllList]get sea patrol note from liveuser response error, code, %d, msg: %s, error:%+v", seaPatrol.Code, seaPatrol.Msg, seaPatrolError)
|
||
return nil
|
||
}
|
||
|
||
if seaPatrol.Data.Title != "" {
|
||
seaPatrolList = append(seaPatrolList, map[string]interface{}{
|
||
"pic": seaPatrol.Data.Logo,
|
||
"title": seaPatrol.Data.Title,
|
||
"link": seaPatrol.Data.Link,
|
||
"content": seaPatrol.Data.Content,
|
||
})
|
||
}
|
||
seaResp.List = seaPatrolList
|
||
seaResp.ModuleInfo = moduleInfo
|
||
seaResp.ExtraInfo = make(map[string]interface{})
|
||
return nil
|
||
})
|
||
}
|
||
|
||
if moduleType == _activityType {
|
||
cardList := module["list"].([]interface{})
|
||
actyInfo := cardList[0].(map[string]interface{})
|
||
bookStatus := jsonMustInt(actyInfo["status"], 0)
|
||
// status=0(非预约类型的活动)
|
||
if bookStatus == _activityGo {
|
||
actyInfo["button_text"] = "去围观"
|
||
actyInfo["status"] = _activityGo
|
||
continue
|
||
}
|
||
// 未登入 显示预约
|
||
if !isUIDSet {
|
||
actyInfo["button_text"] = "预约"
|
||
actyInfo["status"] = _activityBook
|
||
continue
|
||
}
|
||
// 登入状态 设置保底数据
|
||
actyInfo["button_text"] = "去围观"
|
||
actyInfo["status"] = _activityGo
|
||
// 获取活动id
|
||
materialID := jsonMustInt(moduleInfo["material_id"], 0)
|
||
if materialID == 0 {
|
||
continue
|
||
}
|
||
log.Info("[GetAllList]materialID is %v", materialID)
|
||
wg.Go(func() error {
|
||
activityQueryTimeout := time.Duration(conf.GetTimeout("activityQuery", 100)) * time.Millisecond
|
||
bookInfo, userExtError := dao.UserExtApi.V1Remind.Query(rpcCtx.WithTimeout(ctx, activityQueryTimeout), &userextV1.RemindQueryReq{Aid: materialID})
|
||
if userExtError != nil {
|
||
log.Error("[GetAllList]get activity book info rpc error, userext.v1.Remind.Query, error:%+v", userExtError)
|
||
return nil
|
||
}
|
||
if bookInfo.Code != 0 {
|
||
log.Error("[GetAllList]get activity book info response error, code, %d, msg: %s, error:%+v", bookInfo.Code, bookInfo.Msg, userExtError)
|
||
return nil
|
||
}
|
||
log.Info("[GetAllList]materialID is %v and bookInfo.Data.Status is %v", materialID, bookInfo.Data.Status)
|
||
switch bookInfo.Data.Status {
|
||
case _activityBook:
|
||
actyInfo["button_text"] = "已预约"
|
||
actyInfo["status"] = _activityUnbook
|
||
case _activityUnbook:
|
||
actyInfo["button_text"] = "预约"
|
||
actyInfo["status"] = _activityBook
|
||
default:
|
||
actyInfo["button_text"] = "去围观"
|
||
actyInfo["status"] = _activityGo
|
||
}
|
||
return nil
|
||
})
|
||
}
|
||
|
||
// 其他playurl,注意这里取的推荐是未登录下的推荐play_url
|
||
if moduleType == _yunyingRecFormType || moduleType == _yunyingRecSquareType ||
|
||
moduleType == _parentAreaFormType || moduleType == _parentAreaSquareType ||
|
||
moduleType == _recFormType || moduleType == _recSquareType {
|
||
// append Roomid
|
||
for _, item := range moduleList {
|
||
itemV := item.(map[string]interface{})
|
||
roomID := jsonMustInt(itemV["roomid"], 0)
|
||
if roomID == 0 {
|
||
continue
|
||
}
|
||
otherRoomIDSlice = append(otherRoomIDSlice, roomID)
|
||
}
|
||
}
|
||
}
|
||
// +其他模块playurl
|
||
wg.Go(func() error {
|
||
otherRoomListPlayURLMap = dao.BvcApi.GetPlayUrlMulti(ctx, otherRoomIDSlice, 0, 4, build, req.Platform)
|
||
return nil
|
||
})
|
||
|
||
waitErr := wg.Wait()
|
||
if waitErr != nil {
|
||
log.Error("[GetAllList]wait error: %s", waitErr)
|
||
return
|
||
}
|
||
|
||
// 封装
|
||
tagIndex := 0
|
||
for index, m := range rawModuleList {
|
||
module := m.(map[string]interface{})
|
||
moduleInfo := module["module_info"].(map[string]interface{})
|
||
moduleList := module["list"].([]interface{})
|
||
moduleType := jsonMustInt(moduleInfo["type"], 0)
|
||
if moduleType == 0 {
|
||
continue
|
||
}
|
||
// 初始化
|
||
resp.ModuleList[index] = make(map[string]interface{})
|
||
resp.ModuleList[index]["list"] = moduleList
|
||
resp.ModuleList[index]["module_info"] = moduleInfo
|
||
|
||
if moduleType == _bannerType {
|
||
resp.ModuleList[index]["list"] = bannerResp.List
|
||
}
|
||
if moduleType == _navigatorType && req.Platform == "android" && build <= 5333002 {
|
||
// 分区入口5.33版本还返回4个(前3个+全部),5.34透传后台的5个
|
||
if len(moduleList) > 3 {
|
||
resp.ModuleList[index]["list"] = append(moduleList[:3], map[string]interface{}{
|
||
"id": 12,
|
||
"pic": "https://i0.hdslb.com/bfs/vc/ff03528785fc8c91491d79e440398484811d6d87.png",
|
||
"link": "https://live.bilibili.com/app/mytag/",
|
||
"title": "全部标签",
|
||
})
|
||
}
|
||
}
|
||
if moduleType == _seaPatrolType {
|
||
if seaResp.List != nil {
|
||
resp.ModuleList[index]["list"] = seaResp.List
|
||
}
|
||
if seaResp.ModuleInfo != nil {
|
||
resp.ModuleList[index]["module_info"] = seaResp.ModuleInfo
|
||
}
|
||
if seaResp.ExtraInfo != nil {
|
||
resp.ModuleList[index]["extra_info"] = seaResp.ExtraInfo
|
||
}
|
||
}
|
||
if moduleType == _myAreaTagType {
|
||
if myTagResp.List != nil {
|
||
resp.ModuleList[index]["list"] = myTagResp.List
|
||
}
|
||
if myTagResp.ModuleInfo != nil {
|
||
resp.ModuleList[index]["module_info"] = myTagResp.ModuleInfo
|
||
}
|
||
if myTagResp.ExtraInfo != nil {
|
||
resp.ModuleList[index]["extra_info"] = myTagResp.ExtraInfo
|
||
}
|
||
}
|
||
var isTagGray int
|
||
iTmp, _ := myTagResp.ExtraInfo["is_gray"].(int64)
|
||
isTagGray = int(iTmp)
|
||
// 常用分区房间列表填充
|
||
if moduleType == _myAreaTagListType {
|
||
if isTagGray == 0 {
|
||
continue
|
||
}
|
||
if len(myTagAreaIds) == 0 || tagIndex >= len(myTagAreaIds) {
|
||
continue
|
||
}
|
||
mTagAreaID := myTagAreaIds[tagIndex]
|
||
if _, ok := myTagRoomListMap[mTagAreaID]; ok {
|
||
for _, v := range myTagRoomListMap[mTagAreaID] {
|
||
if myTagRoomListPlayURLMap[v.Roomid] != nil {
|
||
v.AcceptQuality = myTagRoomListPlayURLMap[v.Roomid].AcceptQuality
|
||
v.CurrentQuality = myTagRoomListPlayURLMap[v.Roomid].CurrentQuality
|
||
v.PlayUrl = myTagRoomListPlayURLMap[v.Roomid].Url["h264"]
|
||
v.PlayUrlH265 = myTagRoomListPlayURLMap[v.Roomid].Url["h265"]
|
||
}
|
||
}
|
||
resp.ModuleList[index]["list"] = myTagRoomListMap[mTagAreaID]
|
||
if _, ok := myTagAreaInfoMap[mTagAreaID]; ok {
|
||
areaInfo := myTagAreaInfoMap[mTagAreaID]
|
||
moduleInfo["title"] = areaInfo.Name
|
||
moduleInfo["link"] = fmt.Sprintf(_areaModuleLink, areaInfo.ParentId, parentName[areaInfo.ParentId], areaInfo.Id, areaInfo.Name)
|
||
resp.ModuleList[index]["module_info"] = moduleInfo
|
||
}
|
||
}
|
||
tagIndex++
|
||
}
|
||
|
||
// 运营推荐分区对常用分区去重
|
||
if moduleType == _yunyingRecFormType || moduleType == _yunyingRecSquareType {
|
||
link := moduleInfo["link"]
|
||
u, err := url.Parse(link.(string))
|
||
if err != nil {
|
||
log.Warn("[GetAllList]url.Parse (%s) error: %v", link, err)
|
||
continue
|
||
}
|
||
m, err := url.ParseQuery(u.RawQuery)
|
||
if err != nil {
|
||
log.Warn("[GetAllList]url.ParseQuery (%s) error: %v", link, err)
|
||
continue
|
||
}
|
||
area, ok := m["area_id"]
|
||
if !ok {
|
||
log.Warn("[GetAllList]url ((%s) area_id lost: %v", link, ok)
|
||
continue
|
||
}
|
||
|
||
trueArea, err := strconv.Atoi(area[0])
|
||
if err != nil {
|
||
log.Warn("[GetAllList]get trueAreaId error: %v", link, ok)
|
||
continue
|
||
}
|
||
if _, ok := myTagRoomListMap[int64(trueArea)]; ok && isTagGray == 1 {
|
||
resp.ModuleList[index]["list"] = nil
|
||
} else {
|
||
for _, v := range moduleList {
|
||
if v == nil {
|
||
continue
|
||
}
|
||
vv := v.(map[string]interface{})
|
||
roomID := jsonMustInt(vv["roomid"], 0)
|
||
if roomID == 0 {
|
||
continue
|
||
}
|
||
if otherRoomListPlayURLMap[roomID] != nil {
|
||
vv["accept_quality"] = otherRoomListPlayURLMap[roomID].AcceptQuality
|
||
vv["current_quality"] = otherRoomListPlayURLMap[roomID].CurrentQuality
|
||
vv["play_url"] = otherRoomListPlayURLMap[roomID].Url["h264"]
|
||
vv["play_url_h265"] = otherRoomListPlayURLMap[roomID].Url["h265"]
|
||
}
|
||
}
|
||
|
||
resp.ModuleList[index]["list"] = moduleList
|
||
resp.ModuleList[index]["module_info"] = moduleInfo
|
||
}
|
||
}
|
||
|
||
if moduleType == _feedType {
|
||
if attentionResp.ModuleInfo != nil {
|
||
resp.ModuleList[index]["module_info"] = attentionResp.ModuleInfo
|
||
}
|
||
if attentionResp.ExtraInfo != nil {
|
||
resp.ModuleList[index]["extra_info"] = attentionResp.ExtraInfo
|
||
}
|
||
if attentionResp.List != nil {
|
||
for _, v := range attentionResp.List.([]interface{}) {
|
||
vv := v.(*relationV2.AppLiveHomePageResp_Rooms)
|
||
if attentionRoomListPlayURLMap[vv.Roomid] != nil {
|
||
vv.AcceptQuality = attentionRoomListPlayURLMap[vv.Roomid].AcceptQuality
|
||
vv.CurrentQuality = attentionRoomListPlayURLMap[vv.Roomid].CurrentQuality
|
||
vv.PlayUrl = attentionRoomListPlayURLMap[vv.Roomid].Url["h264"]
|
||
vv.PlayUrlH265 = attentionRoomListPlayURLMap[vv.Roomid].Url["h265"]
|
||
}
|
||
}
|
||
resp.ModuleList[index]["list"] = attentionResp.List
|
||
}
|
||
}
|
||
|
||
if moduleType == _recFormType || moduleType == _recSquareType {
|
||
moduleInfo["is_sky_horse_gray"] = isSkyHorseGrayOk
|
||
resp.ModuleList[index]["module_info"] = moduleInfo
|
||
if loginRecResp.List != nil {
|
||
// is uid set
|
||
for _, v := range loginRecResp.List.([]map[string]interface{}) {
|
||
roomID := int64(0)
|
||
r, ok := v["roomid"].(json.Number)
|
||
if ok {
|
||
rr, intErr := r.Int64()
|
||
if intErr != nil {
|
||
continue
|
||
}
|
||
roomID = rr
|
||
} else {
|
||
roomID = v["roomid"].(int64)
|
||
}
|
||
if roomID == 0 {
|
||
continue
|
||
}
|
||
|
||
if loginRecRoomListPlayURLMap[roomID] != nil {
|
||
v["accept_quality"] = loginRecRoomListPlayURLMap[roomID].AcceptQuality
|
||
v["current_quality"] = loginRecRoomListPlayURLMap[roomID].CurrentQuality
|
||
v["play_url"] = loginRecRoomListPlayURLMap[roomID].Url["h264"]
|
||
v["play_url_h265"] = loginRecRoomListPlayURLMap[roomID].Url["h265"]
|
||
}
|
||
}
|
||
resp.ModuleList[index]["list"] = loginRecResp.List
|
||
} else {
|
||
for _, v := range moduleList {
|
||
if v == nil {
|
||
continue
|
||
}
|
||
vv := v.(map[string]interface{})
|
||
roomID := jsonMustInt(vv["roomid"], 0)
|
||
if roomID == 0 {
|
||
continue
|
||
}
|
||
if otherRoomListPlayURLMap[roomID] != nil {
|
||
vv["accept_quality"] = otherRoomListPlayURLMap[roomID].AcceptQuality
|
||
vv["current_quality"] = otherRoomListPlayURLMap[roomID].CurrentQuality
|
||
vv["play_url"] = otherRoomListPlayURLMap[roomID].Url["h264"]
|
||
vv["play_url_h265"] = otherRoomListPlayURLMap[roomID].Url["h265"]
|
||
}
|
||
}
|
||
// 只返24个,新推荐已在上面做处理
|
||
if len(moduleList) > _defaultRecNum {
|
||
resp.ModuleList[index]["list"] = moduleList[:_defaultRecNum]
|
||
} else {
|
||
resp.ModuleList[index]["list"] = moduleList
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
if moduleType == _parentAreaFormType || moduleType == _parentAreaSquareType {
|
||
for _, v := range moduleList {
|
||
if v == nil {
|
||
continue
|
||
}
|
||
vv := v.(map[string]interface{})
|
||
roomID := jsonMustInt(vv["roomid"], 0)
|
||
if roomID == 0 {
|
||
continue
|
||
}
|
||
if otherRoomListPlayURLMap[roomID] != nil {
|
||
vv["accept_quality"] = otherRoomListPlayURLMap[roomID].AcceptQuality
|
||
vv["current_quality"] = otherRoomListPlayURLMap[roomID].CurrentQuality
|
||
vv["play_url"] = otherRoomListPlayURLMap[roomID].Url["h264"]
|
||
vv["play_url_h265"] = otherRoomListPlayURLMap[roomID].Url["h265"]
|
||
}
|
||
}
|
||
resp.ModuleList[index]["list"] = moduleList
|
||
}
|
||
}
|
||
ret = resp
|
||
return
|
||
}
|
||
|
||
func jsonMustInt(arg interface{}, def int64) int64 {
|
||
if arg == nil {
|
||
log.Warn("jsonMustInt arg(%v) nil!", arg)
|
||
return def
|
||
}
|
||
r, ok := arg.(json.Number)
|
||
if !ok {
|
||
log.Warn("jsonMustInt arg(%v) is not json.Number but %v", arg, reflect.TypeOf(arg))
|
||
return def
|
||
}
|
||
rr, err := r.Int64()
|
||
if err != nil {
|
||
log.Warn("jsonMustInt arg(%v) transfer error: %v", arg, err)
|
||
return def
|
||
}
|
||
return rr
|
||
}
|
||
|
||
// Change implementation
|
||
// 首页换一换接口 for 天马
|
||
func (s *Service) Change(ctx context.Context, req *v1indexpb.ChangeReq) (resp *v1indexpb.ChangeResp, err error) {
|
||
resp = &v1indexpb.ChangeResp{
|
||
ModuleList: make([]*v1indexpb.ChangeResp_ModuleList, 0),
|
||
}
|
||
mid, isUIDSet := metadata.Value(ctx, metadata.Mid).(int64)
|
||
|
||
var uid int64
|
||
|
||
if isUIDSet {
|
||
uid = mid
|
||
}
|
||
// deviceInterface, _ := ctx.Get("device")
|
||
// device := req.Device
|
||
|
||
duplicates, _ := xstr.SplitInts(req.AttentionRoomId)
|
||
duplicatesMap := make(map[int64]bool)
|
||
|
||
for _, roomID := range duplicates {
|
||
duplicatesMap[roomID] = true
|
||
}
|
||
build := req.Build
|
||
buvid := ""
|
||
// 主站封好的,可从device里获取到sid、buvid、buvid3、build、channel、device、mobi_app、platform
|
||
device, ok := metadata.Value(ctx, metadata.Device).(*blademaster.Device)
|
||
if ok {
|
||
buvid = device.Buvid
|
||
}
|
||
var recModuleInfo *v1indexpb.ChangeResp_ModuleInfo
|
||
allListOut, callErr := dao.RoomApi.V2AppIndex.GetAllList(rpcCtx.WithTimeout(ctx, 100*time.Millisecond), &roomV2.AppIndexGetAllListReq{
|
||
Platform: req.Platform,
|
||
Device: req.Device,
|
||
Scale: req.Scale,
|
||
Build: int64(build),
|
||
ModuleId: req.ModuleId,
|
||
})
|
||
|
||
if callErr != nil {
|
||
log.Error("[Change]get all list rpc error, room.v2.AppIndex.setAllList, error:%+v", callErr)
|
||
err = errors.WithMessage(ecode.ChangeGetAllListRPCError, "CHANGE GET ALL LIST FAIL#1")
|
||
return
|
||
}
|
||
|
||
if allListOut.Code != 0 || allListOut.Data == nil {
|
||
log.Error("[Change]get all list return data error, code, %d, msg: %s, error:%+v", allListOut.Code, allListOut.Msg, err)
|
||
err = errors.WithMessage(ecode.ChangeGetAllListReturnError, "CHANGE GET ALL LIST FAIL#2")
|
||
return
|
||
}
|
||
|
||
if len(allListOut.Data.ModuleList) == 0 {
|
||
log.Error("[Change]get all list return empty, code, %d, msg: %s, error:%+v", allListOut.Code, allListOut.Msg, err)
|
||
err = errors.WithMessage(ecode.ChangeGetAllListEmptyError, "CHANGE GET ALL LIST FAIL#3")
|
||
return
|
||
}
|
||
|
||
m := allListOut.Data.ModuleList[0]
|
||
duplicateList := make([]*roomV2.AppIndexGetAllListResp_RoomList, 0)
|
||
for _, itemInfo := range m.List {
|
||
if _, ok := duplicatesMap[itemInfo.Roomid]; !ok {
|
||
duplicateList = append(duplicateList, itemInfo)
|
||
}
|
||
}
|
||
|
||
m.List = duplicateList
|
||
|
||
recModuleInfo = &v1indexpb.ChangeResp_ModuleInfo{
|
||
Id: m.ModuleInfo.Id,
|
||
Title: m.ModuleInfo.Title,
|
||
Pic: m.ModuleInfo.Pic,
|
||
Type: m.ModuleInfo.Type,
|
||
Link: m.ModuleInfo.Link,
|
||
Count: m.ModuleInfo.Count,
|
||
IsSkyHorseGray: 0,
|
||
}
|
||
// 目前只有推荐-天马有换一换,都必须有登陆态
|
||
|
||
roomIds := make([]int64, 0)
|
||
list := make([]*v1indexpb.ChangeResp_List, 0)
|
||
for i, itemInfo := range m.List {
|
||
if i >= 24 {
|
||
break
|
||
}
|
||
roomIds = append(roomIds, itemInfo.Roomid)
|
||
list = append(list, &v1indexpb.ChangeResp_List{
|
||
Roomid: itemInfo.Roomid,
|
||
Title: itemInfo.Title,
|
||
Uname: itemInfo.Uname,
|
||
Online: itemInfo.Online,
|
||
Cover: itemInfo.Cover,
|
||
Link: "/" + strconv.Itoa(int(itemInfo.Roomid)),
|
||
Face: itemInfo.Face,
|
||
AreaV2ParentId: itemInfo.AreaV2ParentId,
|
||
AreaV2ParentName: itemInfo.AreaV2ParentName,
|
||
AreaV2Id: itemInfo.AreaV2Id,
|
||
AreaV2Name: itemInfo.AreaV2Name,
|
||
BroadcastType: itemInfo.BroadcastType,
|
||
PendentRu: itemInfo.PendentRu,
|
||
PendentRuPic: itemInfo.PendentRuPic,
|
||
PendentRuColor: itemInfo.PendentRuColor,
|
||
RecType: itemInfo.RecType,
|
||
CurrentQuality: itemInfo.CurrentQuality,
|
||
AcceptQuality: itemInfo.AcceptQuality,
|
||
PlayUrl: itemInfo.PlayUrl,
|
||
})
|
||
}
|
||
|
||
resp.ModuleList = append(resp.ModuleList, &v1indexpb.ChangeResp_ModuleList{
|
||
List: list,
|
||
ModuleInfo: recModuleInfo,
|
||
})
|
||
|
||
isOpen := conf.Conf.SkyHorseStatus
|
||
if isOpen && isUIDSet && s.isSkyHorseRec(uid) {
|
||
recPage := rand.Intn(4)
|
||
if recPage == 1 || recPage == 0 {
|
||
recPage = 2
|
||
}
|
||
recList, skyHorseErr := getSkyHorseRoomList(ctx, uid, buvid, req.Build, req.Platform, duplicates, int64(recPage))
|
||
if skyHorseErr != nil {
|
||
log.Error("[Change]getSkyHorseRoomList error:%+v", skyHorseErr)
|
||
// err = errors.WithMessage(ecode.SkyHorseError, "")
|
||
} else if len(recList) <= 0 {
|
||
log.Error("[Change]getSkyHorseRoomList empty:%+v", recList)
|
||
// err = errors.WithMessage(ecode.ChangeSkyHorseEmptyError, "")
|
||
} else {
|
||
list := make([]*v1indexpb.ChangeResp_List, 0)
|
||
for i, recInfo := range recList {
|
||
if i >= 6 {
|
||
continue
|
||
}
|
||
roomIds = append(roomIds, recInfo.RoomId)
|
||
list = append(list, &v1indexpb.ChangeResp_List{
|
||
Roomid: recInfo.RoomId,
|
||
Title: recInfo.Title,
|
||
Uname: recInfo.Uname,
|
||
Online: recInfo.Online,
|
||
Cover: recInfo.Cover,
|
||
Link: "/" + strconv.Itoa(int(recInfo.RoomId)),
|
||
Face: recInfo.Face,
|
||
AreaV2ParentId: recInfo.AreaV2ParentId,
|
||
AreaV2ParentName: recInfo.AreaV2ParentName,
|
||
AreaV2Id: recInfo.AreaV2Id,
|
||
AreaV2Name: recInfo.AreaV2Name,
|
||
BroadcastType: recInfo.BroadcastType,
|
||
PendentRu: recInfo.PendentRu,
|
||
PendentRuPic: recInfo.PendentRuPic,
|
||
PendentRuColor: recInfo.PendentRuColor,
|
||
RecType: _recTypeSkyHorse,
|
||
})
|
||
}
|
||
skyHorseList := make([]*v1indexpb.ChangeResp_ModuleList, 0)
|
||
recModuleInfo.IsSkyHorseGray = 1
|
||
skyHorseList = append(skyHorseList, &v1indexpb.ChangeResp_ModuleList{
|
||
List: list,
|
||
ModuleInfo: recModuleInfo,
|
||
})
|
||
resp.ModuleList = skyHorseList
|
||
}
|
||
}
|
||
changeRoomListPlayURLMap := dao.BvcApi.GetPlayUrlMulti(ctx, roomIds, 0, 4, build, req.Platform)
|
||
|
||
for _, v := range resp.ModuleList[0].List {
|
||
if changeRoomListPlayURLMap[v.Roomid] != nil {
|
||
v.AcceptQuality = changeRoomListPlayURLMap[v.Roomid].AcceptQuality
|
||
v.CurrentQuality = changeRoomListPlayURLMap[v.Roomid].CurrentQuality
|
||
v.PlayUrl = changeRoomListPlayURLMap[v.Roomid].Url["h264"]
|
||
v.PlayUrlH265 = changeRoomListPlayURLMap[v.Roomid].Url["h265"]
|
||
}
|
||
}
|
||
// 赋值
|
||
return
|
||
}
|
||
|
||
// 获取天马房间信息列表
|
||
// 已将强推roomids传给天马,其他的可通过传duplicates来merge进去
|
||
func getSkyHorseRoomList(ctx context.Context, uid int64, buvid string, build int64, platform string, duplicates []int64, recPage int64) (resp []*roomItem, err error) {
|
||
clientRecStrongTimeout := time.Duration(conf.GetTimeout("clientRecStrong", 100)) * time.Millisecond
|
||
strongRecList, strongRecErr := dao.RoomApi.V1RoomRecommend.ClientRecStrong(rpcCtx.WithTimeout(ctx, clientRecStrongTimeout), &roomV1.RoomRecommendClientRecStrongReq{RecPage: recPage})
|
||
// liverpc.NewClient().CallRaw()
|
||
recDuplicate := make([]int64, 0)
|
||
if strongRecErr != nil {
|
||
log.Error("[getSkyHorseRoomList]room.v1.ClientRecStrong rpc error:%+v", strongRecErr)
|
||
} else if strongRecList.Code != 0 {
|
||
log.Error("[getSkyHorseRoomList]room.v1.ClientRecStrong response error:%+v,code:%d,msg:%s", strongRecErr, strongRecList.Code, strongRecList.Msg)
|
||
} else {
|
||
for _, strongInfo := range strongRecList.Data.Result {
|
||
if strongInfo.Roomid == 0 {
|
||
continue
|
||
}
|
||
recDuplicate = append(recDuplicate, strongInfo.Roomid)
|
||
}
|
||
}
|
||
|
||
strongLen := len(recDuplicate)
|
||
|
||
duplicates = append(duplicates, recDuplicate...)
|
||
skyHorseRec, skyHorseErr := dao.SkyHorseApi.GetSkyHorseRec(ctx, uid, buvid, build, platform, duplicates, strongLen, _skyHorseRecTimeOut)
|
||
if skyHorseErr != nil {
|
||
err = errors.WithMessage(ecode.SkyHorseError, "")
|
||
return
|
||
}
|
||
|
||
roomIds := make([]int64, 0)
|
||
|
||
for _, skyHorseInfo := range skyHorseRec.Data {
|
||
roomIds = append(roomIds, int64(skyHorseInfo.Id))
|
||
}
|
||
|
||
indexRoomListFields := []string{
|
||
"roomid",
|
||
"title",
|
||
"uname",
|
||
"online",
|
||
"cover",
|
||
"user_cover",
|
||
"link",
|
||
"face",
|
||
"area_v2_parent_id",
|
||
"area_v2_parent_name",
|
||
"area_v2_id",
|
||
"area_v2_name",
|
||
"broadcast_type",
|
||
"uid",
|
||
}
|
||
|
||
wg, _ := errgroup.WithContext(ctx)
|
||
|
||
// 房间基础信息(是map,但是天马返回是无序的)
|
||
var multiRoomListResp *roomV2.RoomGetByIdsResp
|
||
wg.Go(func() error {
|
||
getByIdsTimeout := time.Duration(conf.GetTimeout("getByIds", 50)) * time.Millisecond
|
||
multiRoomList, getByIdsError := dao.RoomApi.V2Room.GetByIds(rpcCtx.WithTimeout(ctx, getByIdsTimeout), &roomV2.RoomGetByIdsReq{
|
||
Ids: roomIds,
|
||
NeedBroadcastType: 1,
|
||
NeedUinfo: 1,
|
||
Fields: indexRoomListFields,
|
||
From: "app-interface.gateway",
|
||
})
|
||
if getByIdsError != nil {
|
||
log.Error("[getSkyHorseRoomList]room.v2.getByIds rpc error:%+v", getByIdsError)
|
||
// 这个是推荐房间列表的基础信息,如果失败需要cancel,不然返回值会很奇怪
|
||
return errors.WithMessage(ecode.GetRoomError, "room.v2.getByIds rpc error")
|
||
}
|
||
if multiRoomList.Code != 0 {
|
||
log.Error("[getSkyHorseRoomList]room.v2.getByIds response error:%+v,code:%d,msg:%s", getByIdsError, multiRoomList.Code, multiRoomList.Msg)
|
||
// 这个是推荐房间列表的基础信息,如果失败需要cancel,不然返回值会很奇怪
|
||
return errors.WithMessage(ecode.GetRoomError, "room.v2.getByIds response error")
|
||
}
|
||
multiRoomListResp = multiRoomList
|
||
|
||
return nil
|
||
})
|
||
|
||
// 房间角标信息
|
||
pendantRoomListResp := &roomV1.RoomPendantGetPendantByIdsResp{}
|
||
wg.Go(func() error {
|
||
getPendantByIdsTimeout := time.Duration(conf.GetTimeout("getPendantByIds", 50)) * time.Millisecond
|
||
pendantRoomList, getPendantError := dao.RoomApi.V1RoomPendant.GetPendantByIds(rpcCtx.WithTimeout(ctx, getPendantByIdsTimeout), &roomV1.RoomPendantGetPendantByIdsReq{
|
||
Ids: roomIds,
|
||
Type: "mobile_index_badge",
|
||
Position: 2, // 历史原因,取右上,但客户端展示在左上
|
||
})
|
||
|
||
if getPendantError != nil {
|
||
log.Error("[getSkyHorseRoomList]room.v1.getPendantByIds rpc error:%+v", getPendantError)
|
||
return nil
|
||
}
|
||
if pendantRoomList.Code != 0 {
|
||
log.Error("[getSkyHorseRoomList]room.v1.getPendantByIds response error:%+v,code:%d,msg:%s", getPendantError, pendantRoomList.Code, pendantRoomList.Msg)
|
||
return nil
|
||
}
|
||
pendantRoomListResp = pendantRoomList
|
||
return nil
|
||
})
|
||
|
||
waitErr := wg.Wait()
|
||
if waitErr != nil {
|
||
log.Error("[getSkyHorseRoomList]wait error(%+v)", waitErr)
|
||
return
|
||
}
|
||
|
||
pendantResult := make(map[int64]*roomV1.RoomPendantGetPendantByIdsResp_Result)
|
||
// 天马返回是无序的
|
||
if multiRoomListResp == nil {
|
||
err = errors.WithMessage(ecode.GetRoomEmptyError, "")
|
||
return
|
||
}
|
||
|
||
respSlice := make([]*roomV2.RoomGetByIdsResp_RoomInfo, 0)
|
||
for _, roomBaseInfo := range multiRoomListResp.Data {
|
||
respSlice = append(respSlice, roomBaseInfo)
|
||
}
|
||
for i := 0; i < 6; i++ {
|
||
if strongRecList != nil && strongRecList.Data != nil && strongRecList.Data.Result != nil {
|
||
if recInfo, ok := strongRecList.Data.Result[int64(i)]; ok {
|
||
resp = append(resp, &roomItem{
|
||
RoomId: recInfo.Roomid,
|
||
Title: recInfo.Title,
|
||
Uname: recInfo.Uname,
|
||
Online: recInfo.Online,
|
||
Cover: recInfo.Cover,
|
||
Link: "/" + strconv.Itoa(int(recInfo.Roomid)),
|
||
Face: recInfo.Face,
|
||
AreaV2ParentId: recInfo.AreaV2ParentId,
|
||
AreaV2ParentName: recInfo.AreaV2ParentName,
|
||
AreaV2Id: recInfo.AreaV2Id,
|
||
AreaV2Name: recInfo.AreaV2Name,
|
||
BroadcastType: recInfo.BroadcastType,
|
||
PendentRu: recInfo.PendentRu,
|
||
PendentRuPic: recInfo.PendentRuPic,
|
||
PendentRuColor: recInfo.PendentRuColor,
|
||
RecType: _recTypeForce,
|
||
CurrentQuality: recInfo.CurrentQuality,
|
||
AcceptQuality: recInfo.AcceptQuality,
|
||
})
|
||
continue
|
||
}
|
||
}
|
||
|
||
if len(respSlice) <= 0 {
|
||
continue
|
||
}
|
||
tmpItem := respSlice[0:1][0]
|
||
respSlice = respSlice[1:]
|
||
pendantValue := ""
|
||
pendantBgPic := ""
|
||
pendantBgColor := ""
|
||
if pendantRoomListResp != nil && pendantRoomListResp.Data != nil {
|
||
pendantResult = pendantRoomListResp.Data.Result
|
||
if pendantResult[tmpItem.Roomid] != nil {
|
||
// 移动端取value, web取name
|
||
pendantValue = pendantResult[tmpItem.Roomid].Value
|
||
pendantBgPic = pendantResult[tmpItem.Roomid].BgPic
|
||
if pendantResult[tmpItem.Roomid].BgColor != "" {
|
||
pendantBgColor = pendantResult[tmpItem.Roomid].BgColor
|
||
} else {
|
||
pendantBgColor = _mobileIndexBadgeColorDefault
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
cover := ""
|
||
if tmpItem.UserCover != "" {
|
||
cover = tmpItem.UserCover
|
||
} else {
|
||
cover = tmpItem.Cover
|
||
}
|
||
|
||
resp = append(resp, &roomItem{
|
||
RoomId: tmpItem.Roomid,
|
||
Title: tmpItem.Title,
|
||
Uname: tmpItem.Uname,
|
||
Online: tmpItem.Online,
|
||
Cover: cover,
|
||
Link: "/" + strconv.Itoa(int(tmpItem.Roomid)),
|
||
Face: tmpItem.Face,
|
||
AreaV2ParentId: tmpItem.AreaV2ParentId,
|
||
AreaV2ParentName: tmpItem.AreaV2ParentName,
|
||
AreaV2Id: tmpItem.AreaV2Id,
|
||
AreaV2Name: tmpItem.AreaV2Name,
|
||
BroadcastType: tmpItem.BroadcastType,
|
||
PendentRu: pendantValue,
|
||
PendentRuPic: pendantBgPic,
|
||
PendentRuColor: pendantBgColor,
|
||
RecType: _recTypeSkyHorse,
|
||
})
|
||
}
|
||
|
||
return
|
||
}
|
||
|
||
func (s *Service) isSkyHorseRec(mid int64) bool {
|
||
lastMid := strconv.Itoa(int(mid % 100))
|
||
if len(lastMid) < 2 {
|
||
lastMid = "0" + lastMid
|
||
}
|
||
_, isSkyHorseGray := s.conf.SkyHorseGray[lastMid]
|
||
|
||
return isSkyHorseGray
|
||
}
|
||
|
||
func (s *Service) getAllList(ctx context.Context) (json.RawMessage, error) {
|
||
allListOut, err := dao.RoomRawApi.CallRaw(ctx, 2,
|
||
"AppIndex.getAllRawList", &liverpc.Args{})
|
||
if err != nil {
|
||
log.Error("[getAllList]get all list rpc error, room.v2.AppIndex.getAllRawList, error:%+v", err)
|
||
err = errors.WithMessage(ecode.GetAllListRPCError, "GET ALL LIST FAIL#1")
|
||
return json.RawMessage{}, err
|
||
}
|
||
if allListOut == nil {
|
||
log.Error("[getAllList]get all list raw data nil, room.v2.AppIndex.getAllRawList")
|
||
err = errors.WithMessage(ecode.GetAllListRPCError, "GET ALL LIST FAIL#2")
|
||
return json.RawMessage{}, err
|
||
}
|
||
if allListOut.Code != 0 || allListOut.Data == nil {
|
||
log.Error("[getAllList]get all list return data error, code, %d, msg: %s, error:%+v", allListOut.Code, allListOut.Message, err)
|
||
err = errors.WithMessage(ecode.GetAllListReturnError, "GET ALL LIST FAIL#3")
|
||
return json.RawMessage{}, err
|
||
}
|
||
allListJSONObj, jsonErr := simplejson.NewJson(allListOut.Data)
|
||
if jsonErr != nil {
|
||
log.Error("[getAllList]get all list simplejson error, error:%+v", err)
|
||
err = errors.WithMessage(ecode.GetAllListReturnError, "GET ALL LIST FAIL#4")
|
||
return json.RawMessage{}, err
|
||
}
|
||
|
||
allListCache := allListJSONObj.Get("module_list").MustArray()
|
||
if len(allListCache) > 1 && allListCache[1] == nil {
|
||
log.Error("[getAllList]abnormal module, allListCache:%+v", allListCache)
|
||
err = errors.WithMessage(ecode.GetAllListReturnError, "GET ALL LIST FAIL#5")
|
||
return json.RawMessage{}, err
|
||
}
|
||
|
||
return allListOut.Data, nil
|
||
}
|
||
|
||
func (s *Service) tickCacheAllList(ctx context.Context) {
|
||
ticker := time.NewTicker(5 * time.Second)
|
||
for {
|
||
select {
|
||
case <-ticker.C:
|
||
allListData, err := s.getAllList(ctx)
|
||
if err != nil {
|
||
log.Error("[tickCacheAllList] setAllList error(%+v)", err)
|
||
continue
|
||
}
|
||
if len(allListData) <= 0 {
|
||
log.Error("[tickCacheAllList] setAllList empty data(%+v)", allListData)
|
||
continue
|
||
}
|
||
log.Info("[tickCacheAllList] setAllList success!")
|
||
s.allListInfo.Store(allListData)
|
||
}
|
||
}
|
||
}
|
||
|
||
func (s *Service) getAllListFromCache(ctx context.Context) (allListCache []interface{}) {
|
||
allListRawCache := s.allListInfo.Load()
|
||
|
||
if allListRawCache == nil {
|
||
log.Warn("[getAllListFromCache] cache miss!")
|
||
allList, err := s.getAllList(ctx)
|
||
if err != nil {
|
||
log.Error("[getAllListFromCache] pass through error(%+v)", err)
|
||
}
|
||
allListRawCache = allList
|
||
}
|
||
|
||
allListJSONObj, err := simplejson.NewJson(allListRawCache.(json.RawMessage))
|
||
if err != nil {
|
||
log.Error("[getAllListFromCache]get all list simplejson error, error:%+v", err)
|
||
return
|
||
}
|
||
|
||
allListCache = allListJSONObj.Get("module_list").MustArray()
|
||
if allListCache[1] == nil {
|
||
fmt.Printf("abnormal module, allListRawCache: %+v, module_list: %+v", allListRawCache, allListJSONObj.Get("module_list"))
|
||
}
|
||
log.Info("[getAllListFromCache] cache hit! len: %d", len(allListCache))
|
||
return
|
||
}
|