Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

View File

@ -0,0 +1,97 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"activity_card.go",
"apprelationfilterstrategy.go",
"apprelationsortstrategy.go",
"common.go",
"daowrapper.go",
"index.go",
"live_rec.go",
"live_user.go",
"livehomepage.go",
"pic_list.go",
"rank.go",
"rec_pool.go",
"room_ex.go",
"room_list.go",
"sky_horse.go",
"tools.go",
],
importpath = "go-common/app/interface/live/app-interface/service/v2",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/live/app-interface/api/http/v1:go_default_library",
"//app/interface/live/app-interface/api/http/v2:go_default_library",
"//app/interface/live/app-interface/conf:go_default_library",
"//app/interface/live/app-interface/dao:go_default_library",
"//app/interface/live/app-interface/dao/account:go_default_library",
"//app/interface/live/app-interface/dao/av:go_default_library",
"//app/interface/live/app-interface/dao/fans_medal:go_default_library",
"//app/interface/live/app-interface/dao/live_data:go_default_library",
"//app/interface/live/app-interface/dao/live_user:go_default_library",
"//app/interface/live/app-interface/dao/rankdb:go_default_library",
"//app/interface/live/app-interface/dao/relation:go_default_library",
"//app/interface/live/app-interface/dao/room:go_default_library",
"//app/interface/live/app-interface/dao/room_ex:go_default_library",
"//app/interface/live/app-interface/dao/user_ext:go_default_library",
"//app/interface/live/app-interface/dao/xuser:go_default_library",
"//app/interface/live/app-interface/model:go_default_library",
"//app/interface/live/app-interface/service/v1:go_default_library",
"//app/interface/live/app-interface/service/v1/relation:go_default_library",
"//app/service/live/av/api/liverpc/v1:go_default_library",
"//app/service/live/fans_medal/api/liverpc/v1:go_default_library",
"//app/service/live/live_data/api/liverpc/v1:go_default_library",
"//app/service/live/live_user/api/liverpc/v1:go_default_library",
"//app/service/live/recommend/api/grpc/v1:go_default_library",
"//app/service/live/relation/api/liverpc/v1:go_default_library",
"//app/service/live/room/api/liverpc/v1:go_default_library",
"//app/service/live/room/api/liverpc/v2:go_default_library",
"//app/service/live/room_ex/api/liverpc/v1:go_default_library",
"//app/service/live/third_api/bvc:go_default_library",
"//app/service/live/userext/api/liverpc/v1:go_default_library",
"//app/service/live/xroom-feed/api:go_default_library",
"//app/service/live/xuser/api/grpc/v1:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/main/account/model:go_default_library",
"//app/service/main/account/rpc/client:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/metadata:go_default_library",
"//library/sync/errgroup:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = ["room_list_test.go"],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = ["//app/interface/live/app-interface/conf:go_default_library"],
)

View File

@ -0,0 +1,76 @@
package v2
import (
"context"
v2pb "go-common/app/interface/live/app-interface/api/http/v2"
)
// getActivityCard 活动模块
func (s *IndexService) getActivityCard(ctx context.Context) (resp []*v2pb.MActivityCard) {
resp = []*v2pb.MActivityCard{}
ids := s.getIdsFromModuleMap(ctx, []int64{_activityType})
if len(ids) <= 0 {
return
}
err, activityCardMap := s.roomDao.GetActivityCard(ctx, ids, "GetAllList")
if err != nil {
return
}
listMap := make(map[int64][]*v2pb.ActivityCardItem)
for i, ac := range activityCardMap {
respAc := &v2pb.ActivityCardItem{Room: []*v2pb.RoomCardItem{}, Av: []*v2pb.AvCardItem{}}
respAc.Card = &v2pb.BannerCardItem{
Aid: ac.Card.Aid,
Pic: ac.Card.Pic,
Title: ac.Card.Title,
Text: ac.Card.Text,
PicLink: ac.Card.PicLink,
GoLink: ac.Card.GoLink,
ButtonText: ac.Card.ButtonText,
Status: ac.Card.Status,
Sort: ac.Card.Sort,
}
if len(ac.Room) > 0 {
for _, room := range ac.Room {
roomCard := &v2pb.RoomCardItem{
IsLive: room.IsLive,
RoomId: room.Roomid,
Title: room.Title,
UName: room.Uname,
Online: room.Online,
Cover: room.Cover,
AreaV2ParentId: room.AreaV2ParentId,
AreaV2Id: room.AreaV2Id,
Sort: room.Sort,
}
respAc.Room = append(respAc.Room, roomCard)
}
}
if len(ac.Av) > 0 {
for _, av := range ac.Av {
avCard := &v2pb.AvCardItem{
Avid: av.Avid,
Title: av.Title,
ViewCount: av.ViewCount,
DanMaKu: av.Danmaku,
Duration: av.Duration,
Cover: av.Cover,
Sort: av.Sort,
}
respAc.Av = append(respAc.Av, avCard)
}
}
listMap[i] = append(listMap[i], respAc)
}
moduleInfoMap := s.getAllModuleInfoMap(ctx)
for _, m := range moduleInfoMap[_activityType] {
if l, ok := listMap[m.Id]; ok {
resp = append(resp, &v2pb.MActivityCard{
ModuleInfo: m,
List: l,
})
}
}
return
}

View File

@ -0,0 +1,64 @@
package v2
import (
"context"
v1pb "go-common/app/interface/live/app-interface/api/http/v1"
fansMedalV1 "go-common/app/service/live/fans_medal/api/liverpc/v1"
"go-common/library/log"
)
// const (
// // AppFilterDefault implementation
// // 默认排序
// AppFilterDefault = 0
// // AppFilterFansMedal implementation
// // 只看我有粉丝勋章的
// AppFilterFansMedal = 1
// // AppFilterGoldType implementation
// // 按照金瓜子排序
// AppFilterGoldType = 2
// )
// AppFilterRuleFansMedal implementation
// [app端关注二级页]过滤粉丝勋章
func (s *IndexService) AppFilterRuleFansMedal(ctx context.Context, originResult *v1pb.LiveAnchorResp, targetUIDs []int64) (resp []*v1pb.LiveAnchorResp_Rooms, err error) {
uid := GetUIDFromHeader(ctx)
resp = make([]*v1pb.LiveAnchorResp_Rooms, 0)
if originResult == nil || len(originResult.Rooms) == 0 {
return
}
fansParams := &fansMedalV1.FansMedalTargetsWithMedalReq{Uid: uid, TargetIds: targetUIDs}
hasMedalUIDs, err := s.GetFansMedal(ctx, fansParams)
if err != nil {
log.Error("[LiveAnchor][FilterType]get_FansMedal_rpc_error")
resp = originResult.Rooms
return
}
for _, v := range originResult.Rooms {
if _, exist := hasMedalUIDs[v.Uid]; exist {
resp = append(resp, v)
}
}
return
}
// AppFilterGold implementation
// [app端关注二级页]过滤送礼
func (s *IndexService) AppFilterGold(ctx context.Context, originResult *v1pb.LiveAnchorResp) (resp []*v1pb.LiveAnchorResp_Rooms, err error) {
giftInfo, err := GetGiftInfo(ctx)
resp = make([]*v1pb.LiveAnchorResp_Rooms, 0)
if originResult == nil || len(originResult.Rooms) == 0 {
return
}
if err != nil {
log.Error("[LiveAnchor][FilterType]get_RelationGift_rpc_error")
resp = originResult.Rooms
return
}
for _, v := range originResult.Rooms {
if _, exist := giftInfo[v.Uid]; exist {
resp = append(resp, v)
}
}
return
}

View File

@ -0,0 +1,229 @@
package v2
import (
"context"
v2pb "go-common/app/interface/live/app-interface/api/http/v2"
"go-common/library/log"
"sort"
)
// const (
// // AppSortDefaultT ...
// // 默认排序
// AppSortDefaultT = 0
// // AppSortRuleLiveTimeT ...
// // 开播时间倒序
// AppSortRuleLiveTimeT = 1
// // AppSortRuleOnlineT ...
// // 人气值倒序
// AppSortRuleOnlineT = 2
// // AppSortRuleGoldT ...
// // 金瓜子倒序
// AppSortRuleGoldT = 3
// )
// SendGift ...
// [app端关注二级页]按照金瓜子排序结构
type SendGift struct {
Mid int64
gold int64
}
// SortLiveTime ... implementation
// [app端关注二级页]按照开播时间排序
type SortLiveTime []*v2pb.MyIdolItem
// SortOnlineTime ... implementation
// [app端关注二级页]按照房间人气值排序
type SortOnlineTime []*v2pb.MyIdolItem
// SortUIDGift ... implementation
// [app端关注二级页]按照送礼排序
type SortUIDGift []SendGift
// AppSortRuleLiveTime implementation
// [app端关注二级页]按照开播时间排序
func (p SortLiveTime) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// AppSortRuleLiveTime implementation
// [app端关注二级页]按照开播时间排序
func (p SortLiveTime) Len() int { return len(p) }
// AppSortRuleLiveTime implementation
// [app端关注二级页]按照开播时间排序
func (p SortLiveTime) Less(i, j int) bool { return p[i].LiveTime > p[j].LiveTime }
// AppSortRuleLiveTime implementation
// [app端关注二级页]按照开播时间排序
func (p SortOnlineTime) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// AppSortRuleLiveTime implementation
// [app端关注二级页]按照开播时间排序
func (p SortOnlineTime) Len() int { return len(p) }
// AppSortRuleLiveTime implementation
// [app端关注二级页]按照开播时间排序
func (p SortOnlineTime) Less(i, j int) bool { return p[i].Online > p[j].Online }
// Swap
// [app端关注二级页]自定义排序结构
func (p SortUIDGift) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// Len
// [app端关注二级页]自定义排序结构
func (p SortUIDGift) Len() int { return len(p) }
// Less
// [app端关注二级页]自定义排序结构
func (p SortUIDGift) Less(i, j int) bool { return p[i].gold > p[j].gold }
// AppSortRuleLiveTime implementation
// [app端关注二级页]按照开播时间排序
func (s *IndexService) AppSortRuleLiveTime(originResult []*v2pb.MyIdolItem) (resp []*v2pb.MyIdolItem) {
resp = make([]*v2pb.MyIdolItem, 0)
if originResult == nil {
return
}
p := make(SortLiveTime, len(originResult))
i := 0
for _, v := range originResult {
p[i] = &v2pb.MyIdolItem{
Roomid: v.Roomid,
Uid: v.Uid,
Uname: v.Uname,
Face: v.Face,
Title: v.Title,
LiveTagName: v.LiveTagName,
LiveTime: v.LiveTime,
Online: v.Online,
PlayUrl: v.PlayUrl,
AcceptQuality: v.AcceptQuality,
CurrentQuality: v.CurrentQuality,
PkId: v.PkId,
SpecialAttention: v.SpecialAttention,
Area: v.Area,
AreaName: v.AreaName,
AreaV2Id: v.AreaV2Id,
AreaV2Name: v.AreaV2Name,
AreaV2ParentName: v.AreaV2ParentName,
AreaV2ParentId: v.AreaV2ParentId,
BroadcastType: v.BroadcastType,
OfficialVerify: v.OfficialVerify,
Link: v.Link,
Cover: v.Cover,
PendentRu: v.PendentRu,
PendentRuColor: v.PendentRuColor,
PendentRuPic: v.PendentRuPic}
i++
}
sort.Sort(p)
resp = p
return
}
// AppSortRuleOnline implementation
// [app端关注二级页]按照人气值排序
func AppSortRuleOnline(originResult []*v2pb.MyIdolItem) (resp []*v2pb.MyIdolItem) {
resp = make([]*v2pb.MyIdolItem, 0)
if originResult == nil {
return
}
p := make(SortOnlineTime, len(originResult))
i := 0
for _, v := range originResult {
p[i] = &v2pb.MyIdolItem{
Roomid: v.Roomid,
Uid: v.Uid,
Uname: v.Uname,
Face: v.Face,
Title: v.Title,
LiveTagName: v.LiveTagName,
LiveTime: v.LiveTime,
Online: v.Online,
PlayUrl: v.PlayUrl,
AcceptQuality: v.AcceptQuality,
CurrentQuality: v.CurrentQuality,
PkId: v.PkId,
SpecialAttention: v.SpecialAttention,
Area: v.Area,
AreaName: v.AreaName,
AreaV2Id: v.AreaV2Id,
AreaV2Name: v.AreaV2Name,
AreaV2ParentName: v.AreaV2ParentName,
AreaV2ParentId: v.AreaV2ParentId,
BroadcastType: v.BroadcastType,
OfficialVerify: v.OfficialVerify,
Link: v.Link,
Cover: v.Cover,
PendentRu: v.PendentRu,
PlayUrlH265: v.PlayUrlH265,
PendentRuColor: v.PendentRuColor,
PendentRuPic: v.PendentRuPic}
i++
}
sort.Sort(p)
resp = p
return
}
// AppSortRuleGold implementation
// [app端关注二级页]按照送礼排序
func (s *IndexService) AppSortRuleGold(ctx context.Context, originResult *v2pb.MMyIdol) (resp []*v2pb.MyIdolItem) {
resp = make([]*v2pb.MyIdolItem, 0)
if originResult == nil {
return
}
giftInfo, err := GetGiftInfo(ctx)
if err != nil {
log.Error("[LiveAnchor][FilterType][AppSortRuleGold]get_RelationGift_rpc_error")
resp = originResult.List
return
}
if len(giftInfo) == 0 {
resp = AppSortRuleOnline(originResult.List)
return
}
respHasGold := make([]*v2pb.MyIdolItem, 0)
respNoGold := make([]*v2pb.MyIdolItem, 0)
GiftRank := make(map[int64]int64)
GiftNoGold := make([]int64, 0)
// 计算金瓜子排行榜,uid分key
for _, v := range originResult.List {
roomUID := v.Uid
if _, exist := giftInfo[roomUID]; exist {
GiftRank[roomUID] += giftInfo[roomUID]
}
}
sorted := SortMap(GiftRank)
// 没有送礼的用户
for _, v := range originResult.List {
if _, exist := GiftRank[v.Uid]; !exist {
GiftNoGold = append(GiftNoGold, v.Uid)
}
}
for _, vv := range sorted {
for _, v := range originResult.List {
if v.Uid == vv.Key {
respHasGold = append(respHasGold, v)
}
}
}
for _, v := range originResult.List {
for _, vv := range GiftNoGold {
if v.Uid == vv {
respNoGold = append(respNoGold, v)
}
}
}
tempLiveAnchor := &v2pb.MMyIdol{}
tempLiveAnchor.List = respNoGold
respNoGoldSorted := AppSortRuleOnline(tempLiveAnchor.List)
resp = append(resp, respHasGold...)
resp = append(resp, respNoGoldSorted...)
return
}

View File

@ -0,0 +1,235 @@
package v2
import (
"context"
"strconv"
"go-common/app/interface/live/app-interface/dao"
"go-common/app/interface/live/app-interface/model"
"go-common/app/service/main/account/api"
v2pb "go-common/app/interface/live/app-interface/api/http/v2"
"go-common/app/interface/live/app-interface/conf"
roomV1 "go-common/app/service/live/room/api/liverpc/v1"
roomV2 "go-common/app/service/live/room/api/liverpc/v2"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
// 统一cover获取方式
func (s *IndexService) getCover(userCover string, systemCover string) (cover string) {
if userCover != "" {
cover = userCover
} else {
cover = systemCover
}
return
}
func (s *IndexService) ifHitSkyHorse(mid int64, device string) (hit bool) {
if mid == 0 {
return false
}
if device == "pad" {
return false
}
lastMid := strconv.Itoa(int(mid % 100))
if len(lastMid) < 2 {
lastMid = "0" + lastMid
}
_, isSkyHorseGray := s.conf.SkyHorseGray[lastMid]
return isSkyHorseGray && conf.Conf.SkyHorseStatus
}
func (s *IndexService) ifHitLiveRec(mid int64, device string) (hit bool) {
if mid == 0 {
return false
}
if device == "pad" {
return false
}
lastMid := strconv.Itoa(int(mid % 100))
if len(lastMid) < 2 {
lastMid = "0" + lastMid
}
_, isLiveRec := s.conf.LiveGray[lastMid]
return isLiveRec
}
func (s *IndexService) getRecRoomList(ctx context.Context, roomIds []int64, recPoolRoomListResp map[int64]*v2pb.CommonRoomItem, build int64, platform string, idolDuplicateMap map[int64]bool, recType int64, quality int64) (respRecRoomList []*v2pb.CommonRoomItem, err error) {
wg, wgCtx := errgroup.WithContext(ctx)
multiRoomListResp := make(map[int64]*roomV2.RoomGetByIdsResp_RoomInfo)
wg.Go(func() error {
// 天马房间基础信息,有错误cancel其他没必要执行
fields := []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",
}
multiRoomList, err := s.roomDao.GetRoomInfoByIds(wgCtx, roomIds, fields, "app-interface-skyHorseRec")
if err != nil {
log.Error("[getRecRoomList]getByIds error:%+v", err)
}
multiRoomListResp = multiRoomList
return err
})
pendantRoomListResp := make(map[int64]*roomV1.RoomPendantGetPendantByIdsResp_Result)
wg.Go(func() error {
pendantRoomList, err := s.roomDao.GetRoomPendant(wgCtx, roomIds, "mobile_index_badge", 2)
if err != nil {
log.Error("[getRecRoomList]getPendantByIds error:%+v", err)
}
pendantRoomListResp = pendantRoomList
return nil
})
err = wg.Wait()
if err != nil {
log.Error("[getRecRoomList]wait error(%+v)", err)
return
}
respSlice := make([]*roomV2.RoomGetByIdsResp_RoomInfo, 0)
for _, roomBaseInfo := range multiRoomListResp {
respSlice = append(respSlice, roomBaseInfo)
}
respRecRoomList = make([]*v2pb.CommonRoomItem, 0)
for i := 0; i < 6; i++ {
if recInfo, ok := recPoolRoomListResp[int64(i+1)]; ok {
if _, ok := idolDuplicateMap[recInfo.Roomid]; !ok {
respRecRoomList = append(respRecRoomList, recInfo)
continue
}
}
if len(respSlice) <= 0 {
continue
}
tmpItem := respSlice[0:1][0]
respSlice = respSlice[1:]
pendantValue, pendantBgPic, pendantBgColor := s.getPendant(tmpItem.Roomid, pendantRoomListResp)
// 统一cover产品逻辑
cover := s.getCover(tmpItem.UserCover, tmpItem.Cover)
respRecRoomList = append(respRecRoomList, &v2pb.CommonRoomItem{
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: recType,
})
}
s.getPlayUrl(ctx, respRecRoomList, quality, build, platform)
return
}
func (s *IndexService) getExtraDataForRoom(ctx context.Context, roomIds []int64, uids []int64, roomIdToUid map[int64]int64) (extraInfo map[int64]*model.ExtraRecInfo) {
wg, wgCtx := errgroup.WithContext(ctx)
extraInfo = make(map[int64]*model.ExtraRecInfo)
userInfos := make(map[int64]*api.Info)
wg.Go(func() error {
userResult, err := s.accountDao.GetUserInfos(wgCtx, uids)
if err != nil {
log.Error("[getExtraDataForRoom]getByIds error:%+v", err)
}
userInfos = userResult
return err
})
pendantRoomListResp := make(map[int64]*roomV1.RoomPendantGetPendantByIdsResp_Result)
wg.Go(func() error {
pendantRoomList, err := s.roomDao.GetRoomPendant(wgCtx, roomIds, "mobile_index_badge", 2)
if err != nil {
log.Error("[getExtraDataForRoom]getPendantByIds error:%+v", err)
}
pendantRoomListResp = pendantRoomList
return nil
})
err := wg.Wait()
if err != nil {
log.Error("[getExtraDataForRoom]getExtraDataForRoom_waitError:%+v", err)
return
}
for _, roomId := range roomIds {
pendantValue, pendantBgPic, pendantBgColor := s.getPendant(roomId, pendantRoomListResp)
if _, ok := extraInfo[roomId]; !ok {
extraInfo[roomId] = &model.ExtraRecInfo{}
}
extraInfo[roomId].PendentRu = pendantValue
extraInfo[roomId].PendentRuPic = pendantBgPic
extraInfo[roomId].PendentRuColor = pendantBgColor
if uid, ok := roomIdToUid[roomId]; ok {
if _, ok := userInfos[uid]; ok {
extraInfo[roomId].UName = userInfos[uid].Name
extraInfo[roomId].Face = userInfos[uid].Face
}
}
}
return
}
func (s *IndexService) getPendant(roomId int64, pendantRoomListResp map[int64]*roomV1.RoomPendantGetPendantByIdsResp_Result) (pendantValue, pendantBgPic, pendantBgColor string) {
if pendantRoomListResp != nil {
if _, ok := pendantRoomListResp[roomId]; ok {
// 移动端取value, web取name
pendantValue = pendantRoomListResp[roomId].Value
pendantBgPic = pendantRoomListResp[roomId].BgPic
if pendantRoomListResp[roomId].BgColor != "" {
pendantBgColor = pendantRoomListResp[roomId].BgColor
} else {
pendantBgColor = _mobileIndexBadgeColorDefault
}
}
}
return
}
func (s *IndexService) getPlayUrl(ctx context.Context, roomList []*v2pb.CommonRoomItem, quality, build int64, platform string) {
roomIdsForPlayUrl := make([]int64, 0)
for _, commRoomBlock := range roomList {
roomIdsForPlayUrl = append(roomIdsForPlayUrl, commRoomBlock.Roomid)
}
changeRoomListPlayURLMap := dao.BvcApi.GetPlayUrlMulti(ctx, roomIdsForPlayUrl, 0, quality, build, platform)
for _, vv := range roomList {
if changeRoomListPlayURLMap[vv.Roomid] != nil {
vv.AcceptQuality = changeRoomListPlayURLMap[vv.Roomid].AcceptQuality
vv.CurrentQuality = changeRoomListPlayURLMap[vv.Roomid].CurrentQuality
vv.PlayUrl = changeRoomListPlayURLMap[vv.Roomid].Url["h264"]
vv.PlayUrlH265 = changeRoomListPlayURLMap[vv.Roomid].Url["h265"]
}
}
}

View File

@ -0,0 +1,572 @@
package v2
import (
"context"
"math"
"strconv"
"github.com/pkg/errors"
ServiceConf "go-common/app/interface/live/app-interface/conf"
"go-common/app/interface/live/app-interface/dao"
relationT "go-common/app/interface/live/app-interface/service/v1/relation"
avV1 "go-common/app/service/live/av/api/liverpc/v1"
fansMedalV1 "go-common/app/service/live/fans_medal/api/liverpc/v1"
liveDataV1 "go-common/app/service/live/live_data/api/liverpc/v1"
relationV1 "go-common/app/service/live/relation/api/liverpc/v1"
roomV1 "go-common/app/service/live/room/api/liverpc/v1"
roomV2 "go-common/app/service/live/room/api/liverpc/v2"
roomExV1 "go-common/app/service/live/room_ex/api/liverpc/v1"
userExV1 "go-common/app/service/live/userext/api/liverpc/v1"
liveUserExpM "go-common/app/service/live/xuser/api/grpc/v1"
accountM "go-common/app/service/main/account/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
// ChunkCallInfo ...
// 日志结构体
type ChunkCallInfo struct {
ParamsName string
URLName string
ChunkSize int64
ChunkNum int64
RPCTimeout int64
}
const (
// GoRoutingErr ...
// 协程wait错误
GoRoutingErr = "协程等待数据错误"
)
// UIDs2roomIDs ...
// uid转换roomID,每批最大400
func (s *IndexService) UIDs2roomIDs(ctx context.Context, UIDs []int64) (roomIDs map[int64]int64, err error) {
rpcChunkSize, RPCTimeout, err := relationT.GetChunkInfo(ServiceConf.GetRoomID)
params := ServiceConf.ChunkCallInfo{ParamsName: "uids", URLName: ServiceConf.GetRoomID, ChunkSize: rpcChunkSize, RPCTimeout: RPCTimeout}
roomIDs = make(map[int64]int64)
lens := len(UIDs)
if lens <= 0 {
return
}
// 批次
params.ChunkNum = int64(math.Ceil(float64(lens) / float64(params.ChunkSize)))
chunkResult := make([]map[string]string, params.ChunkNum)
wg, _ := errgroup.WithContext(ctx)
for i := int64(1); i <= params.ChunkNum; i++ {
x := i
wg.Go(func() error {
chunkUfosIds := make([]int64, 20)
if x == params.ChunkNum {
chunkUfosIds = UIDs[(x-1)*params.ChunkSize:]
} else {
chunkUfosIds = UIDs[(x-1)*params.ChunkSize : x*params.ChunkSize]
}
ret, err := s.roomDao.UIDs2roomIDs(ctx, &roomV2.RoomRoomIdByUidMultiReq{Uids: chunkUfosIds}, params)
if err != nil {
return err
}
chunkResult[x-1] = ret.Data
return nil
})
}
if err := wg.Wait(); err != nil {
erelongInfo := ServiceConf.ErrLogStrut{}
erelongInfo.ErrType = "GoRoutingWaitError"
erelongInfo.URLName = ServiceConf.GetRoomID
erelongInfo.ErrDesc = GoRoutingErr
erelongInfo.Code = 1003001
erelongInfo.RPCTimeout = params.RPCTimeout
erelongInfo.ErrorPtr = &err
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s",
*erelongInfo.ErrorPtr, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName)
err = errors.WithMessage(ecode.RelationFrameWorkGoRoutingError, "GET SEA PATROL FAIL")
return nil, err
}
// 整理数据
for _, chunkItemList := range chunkResult {
for k, item := range chunkItemList {
if item != "" {
Index := RParseInt(k, 1)
itemInt := RParseInt(item, 1)
roomIDs[Index] = itemInt
}
}
}
return
}
// GetRoomInfo ...
// 获取room信息
func (s *IndexService) GetRoomInfo(ctx context.Context, input *roomV1.RoomGetStatusInfoByUidsReq) (roomResult map[int64]*roomV1.RoomGetStatusInfoByUidsResp_RoomInfo, err error) {
rpcChunkSize, RPCTimeout, err := relationT.GetChunkInfo(ServiceConf.GetStatusInfoByUfos)
params := ServiceConf.ChunkCallInfo{ParamsName: "uids", URLName: ServiceConf.GetStatusInfoByUfos, ChunkSize: rpcChunkSize, RPCTimeout: RPCTimeout}
roomResult = make(map[int64]*roomV1.RoomGetStatusInfoByUidsResp_RoomInfo)
lens := len(input.Uids)
if lens <= 0 {
return
}
// 批次
params.ChunkNum = int64(math.Ceil(float64(lens) / float64(params.ChunkSize)))
chunkResult := make([]map[int64]*roomV1.RoomGetStatusInfoByUidsResp_RoomInfo, params.ChunkNum)
wg, _ := errgroup.WithContext(ctx)
for i := int64(1); i <= params.ChunkNum; i++ {
x := i
wg.Go(func() error {
chunkUfosIds := make([]int64, 20)
if x == params.ChunkNum {
chunkUfosIds = input.Uids[(x-1)*params.ChunkSize:]
} else {
chunkUfosIds = input.Uids[(x-1)*params.ChunkSize : x*params.ChunkSize]
}
ret, err := s.roomDao.GetRoomInfo(ctx, &roomV1.RoomGetStatusInfoByUidsReq{Uids: chunkUfosIds, FilterOffline: input.FilterOffline, NeedBroadcastType: input.NeedBroadcastType}, params)
if err != nil {
return err
}
chunkResult[x-1] = ret.Data
return nil
})
}
if err := wg.Wait(); err != nil {
erelongInfo := ServiceConf.ErrLogStrut{}
erelongInfo.ErrType = "GoRoutingWaitError"
erelongInfo.URLName = ServiceConf.GetStatusInfoByUfos
erelongInfo.ErrDesc = GoRoutingErr
erelongInfo.Code = 1003001
erelongInfo.RPCTimeout = params.RPCTimeout
erelongInfo.ErrorPtr = &err
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s",
*erelongInfo.ErrorPtr, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName)
err = errors.WithMessage(ecode.RoomFrameWorkGoRoutingError, "GET SEA PATROL FAIL")
return nil, err
}
// 整理数据
for _, chunkItemList := range chunkResult {
for _, item := range chunkItemList {
if item != nil {
roomResult[item.Uid] = item
}
}
}
return
}
// GetLastLiveTime ...
// 获取Record信息
func (s *IndexService) GetLastLiveTime(ctx context.Context, rolaids []int64) (resp map[string]string, err error) {
rpcChunkSize, RPCTimeout, err := relationT.GetChunkInfo(ServiceConf.Record)
params := ServiceConf.ChunkCallInfo{ParamsName: "uids", URLName: ServiceConf.Record, ChunkSize: rpcChunkSize, RPCTimeout: RPCTimeout}
resp = make(map[string]string)
lens := len(rolaids)
if lens <= 0 {
return
}
// 批次
params.ChunkNum = int64(math.Ceil(float64(lens) / float64(params.ChunkSize)))
chunkResult := make([]map[string]*liveDataV1.RecordGetResp_TimeInfo, params.ChunkNum)
wg, _ := errgroup.WithContext(ctx)
for i := int64(1); i <= params.ChunkNum; i++ {
x := i
wg.Go(func() error {
chunkRoomIds := make([]int64, 20)
if x == params.ChunkNum {
chunkRoomIds = rolaids[(x-1)*params.ChunkSize:]
} else {
chunkRoomIds = rolaids[(x-1)*params.ChunkSize : x*params.ChunkSize]
}
ret, err := s.livedataDao.GetLastLiveTime(ctx, &liveDataV1.RecordGetReq{Roomids: chunkRoomIds}, params)
if err != nil {
return err
}
chunkResult[x-1] = ret
return nil
})
}
if err := wg.Wait(); err != nil {
erelongInfo := ServiceConf.ErrLogStrut{}
erelongInfo.ErrType = "GoRoutingWaitError"
erelongInfo.URLName = ServiceConf.Record
erelongInfo.ErrDesc = GoRoutingErr
erelongInfo.Code = 1003001
erelongInfo.RPCTimeout = params.RPCTimeout
erelongInfo.ErrorPtr = &err
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s",
*erelongInfo.ErrorPtr, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName)
err = errors.WithMessage(ecode.RecordFrameWorkGoRoutingError, "GET SEA PATROL FAIL")
return nil, err
}
// 整理数据
for _, chunkItemList := range chunkResult {
for k, item := range chunkItemList {
if item != nil {
resp[k] = item.RecentEndTime
}
}
}
return
}
// GetRoomNewsInfo ...
// 获取公告信息
func (s *IndexService) GetRoomNewsInfo(ctx context.Context, rolaids *roomExV1.RoomNewsMultiGetReq) (roomNewsResult map[int64]*roomExV1.RoomNewsMultiGetResp_Data, err error) {
rpcChunkSize, RPCTimeout, err := relationT.GetChunkInfo(ServiceConf.RoomNews)
params := ServiceConf.ChunkCallInfo{ParamsName: "roomids", URLName: ServiceConf.RoomNews, ChunkSize: rpcChunkSize, RPCTimeout: RPCTimeout}
roomNewsResult = make(map[int64]*roomExV1.RoomNewsMultiGetResp_Data)
lens := len(rolaids.RoomIds)
if lens <= 0 {
return
}
// 批次
params.ChunkNum = int64(math.Ceil(float64(lens) / float64(params.ChunkSize)))
chunkResult := make([][]*roomExV1.RoomNewsMultiGetResp_Data, params.ChunkNum)
wg, _ := errgroup.WithContext(ctx)
for i := int64(1); i <= params.ChunkNum; i++ {
x := i
wg.Go(func() error {
chunkRoomIds := make([]int64, 20)
if x == params.ChunkNum {
chunkRoomIds = rolaids.RoomIds[(x-1)*params.ChunkSize:]
} else {
chunkRoomIds = rolaids.RoomIds[(x-1)*params.ChunkSize : x*params.ChunkSize]
}
ret, err := s.roomexDao.GetRoomNewsInfo(ctx, &roomExV1.RoomNewsMultiGetReq{RoomIds: chunkRoomIds, IsDecoded: rolaids.IsDecoded}, params)
if err != nil {
return err
}
chunkResult[x-1] = ret.Data
return nil
})
}
if err := wg.Wait(); err != nil {
erelongInfo := ServiceConf.ErrLogStrut{}
erelongInfo.ErrType = "GoRoutingWaitError"
erelongInfo.URLName = ServiceConf.RoomNews
erelongInfo.ErrDesc = GoRoutingErr
erelongInfo.Code = 1003001
erelongInfo.RPCTimeout = params.RPCTimeout
erelongInfo.ErrorPtr = &err
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s",
*erelongInfo.ErrorPtr, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName)
err = errors.WithMessage(ecode.RoomNewsFrameWorkGoRoutingError, "GET SEA PATROL FAIL")
return nil, err
}
// 整理数据
for _, chunkItemList := range chunkResult {
for _, item := range chunkItemList {
if item != nil {
if mid, err := strconv.ParseInt(item.Roomid, 10, 64); err == nil {
roomNewsResult[mid] = item
}
}
}
}
return
}
// GetRoomPendantInfo ...
// 获取角标信息
func (s *IndexService) GetRoomPendantInfo(ctx context.Context, req *roomV1.RoomPendantGetPendantByIdsReq) (roomNewsResult map[int64]*roomV1.RoomPendantGetPendantByIdsResp_Result, err error) {
rpcChunkSize, RPCTimeout, err := relationT.GetChunkInfo(ServiceConf.RoomPendent)
params := ServiceConf.ChunkCallInfo{ParamsName: "ids", URLName: ServiceConf.RoomPendent, ChunkSize: rpcChunkSize, RPCTimeout: RPCTimeout}
roomNewsResult = make(map[int64]*roomV1.RoomPendantGetPendantByIdsResp_Result)
lens := len(req.Ids)
if lens <= 0 {
return
}
// 批次
params.ChunkNum = int64(math.Ceil(float64(lens) / float64(params.ChunkSize)))
chunkResult := make([]map[int64]*roomV1.RoomPendantGetPendantByIdsResp_Result, params.ChunkNum)
wg, _ := errgroup.WithContext(ctx)
for i := int64(1); i <= params.ChunkNum; i++ {
x := i
wg.Go(func() error {
chunkRoomIds := make([]int64, 20)
if x == params.ChunkNum {
chunkRoomIds = req.Ids[(x-1)*params.ChunkSize:]
} else {
chunkRoomIds = req.Ids[(x-1)*params.ChunkSize : x*params.ChunkSize]
}
ret, err := s.roomDao.GetRoomPendantInfo(ctx, &roomV1.RoomPendantGetPendantByIdsReq{Ids: chunkRoomIds, Type: req.Type, Position: req.Position}, params)
if err != nil || ret == nil {
return err
}
chunkResult[x-1] = ret.Data.Result
return nil
})
}
if err := wg.Wait(); err != nil {
erelongInfo := ServiceConf.ErrLogStrut{}
erelongInfo.ErrType = "GoRoutingWaitError"
erelongInfo.URLName = ServiceConf.RoomPendent
erelongInfo.ErrDesc = GoRoutingErr
erelongInfo.Code = 1003001
erelongInfo.RPCTimeout = params.RPCTimeout
erelongInfo.ErrorPtr = &err
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s",
*erelongInfo.ErrorPtr, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName)
err = errors.WithMessage(ecode.RoomPendentFrameWorkGoRoutingError, "GET SEA PATROL FAIL")
return nil, err
}
// 整理数据
for _, chunkItemList := range chunkResult {
for k, item := range chunkItemList {
if item != nil {
roomNewsResult[k] = item
}
}
}
return
}
// GetPkID ...
// 获取PkId信息
func (s *IndexService) GetPkID(ctx context.Context, req *avV1.PkGetPkIdsByRoomIdsReq) (avResult map[string]int64, err error) {
rpcChunkSize, RPCTimeout, err := relationT.GetChunkInfo(ServiceConf.GetPkIdsByRoomIds)
params := ServiceConf.ChunkCallInfo{ParamsName: "ids", URLName: ServiceConf.GetPkIdsByRoomIds, ChunkSize: rpcChunkSize, RPCTimeout: RPCTimeout}
avResult = make(map[string]int64)
lens := len(req.RoomIds)
if lens <= 0 {
return
}
// 批次
params.ChunkNum = int64(math.Ceil(float64(lens) / float64(params.ChunkSize)))
chunkResult := make([]map[string]int64, params.ChunkNum)
wg, _ := errgroup.WithContext(ctx)
for i := int64(1); i <= params.ChunkNum; i++ {
x := i
wg.Go(func() error {
chunkRoomIds := make([]int64, 20)
if x == params.ChunkNum {
chunkRoomIds = req.RoomIds[(x-1)*params.ChunkSize:]
} else {
chunkRoomIds = req.RoomIds[(x-1)*params.ChunkSize : x*params.ChunkSize]
}
ret, err := s.avDao.GetPkID(ctx, &avV1.PkGetPkIdsByRoomIdsReq{RoomIds: chunkRoomIds, Platform: req.Platform}, params)
if err != nil {
return err
}
chunkResult[x-1] = ret.Data
return nil
})
}
if err := wg.Wait(); err != nil {
erelongInfo := ServiceConf.ErrLogStrut{}
erelongInfo.ErrType = "GoRoutingWaitError"
erelongInfo.URLName = ServiceConf.GetPkIdsByRoomIds
erelongInfo.ErrDesc = GoRoutingErr
erelongInfo.Code = 1003001
erelongInfo.RPCTimeout = params.RPCTimeout
erelongInfo.ErrorPtr = &err
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s",
*erelongInfo.ErrorPtr, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName)
err = errors.WithMessage(ecode.PkIDFrameWorkGoRoutingError, "GET SEA PATROL FAIL")
return nil, err
}
// 整理数据
for _, chunkItemList := range chunkResult {
for k, item := range chunkItemList {
avResult[k] = item
}
}
return
}
// GetFansMedal ...
// 获取粉丝勋章佩戴信息
func (s *IndexService) GetFansMedal(ctx context.Context, req *fansMedalV1.FansMedalTargetsWithMedalReq) (fansResult map[int64]bool, err error) {
rpcChunkSize, RPCTimeout, err := relationT.GetChunkInfo(ServiceConf.TargetsWithMedal)
params := ServiceConf.ChunkCallInfo{ParamsName: "ids", URLName: ServiceConf.TargetsWithMedal, ChunkSize: rpcChunkSize, RPCTimeout: RPCTimeout}
fansResult = make(map[int64]bool)
lens := len(req.TargetIds)
if lens <= 0 {
return
}
// 批次
params.ChunkNum = int64(math.Ceil(float64(lens) / float64(params.ChunkSize)))
chunkResult := make([][]int64, params.ChunkNum)
wg, _ := errgroup.WithContext(ctx)
for i := int64(1); i <= params.ChunkNum; i++ {
x := i
wg.Go(func() error {
chunkRoomIds := make([]int64, 20)
if x == params.ChunkNum {
chunkRoomIds = req.TargetIds[(x-1)*params.ChunkSize:]
} else {
chunkRoomIds = req.TargetIds[(x-1)*params.ChunkSize : x*params.ChunkSize]
}
ret, err := s.fansMedalDao.GetFansMedal(ctx, &fansMedalV1.FansMedalTargetsWithMedalReq{Uid: req.Uid, TargetIds: chunkRoomIds}, params)
if err != nil {
return err
}
chunkResult[x-1] = ret.Data
return nil
})
}
if err := wg.Wait(); err != nil {
erelongInfo := ServiceConf.ErrLogStrut{}
erelongInfo.ErrType = "GoRoutingWaitError"
erelongInfo.URLName = ServiceConf.TargetsWithMedal
erelongInfo.ErrDesc = GoRoutingErr
erelongInfo.Code = 1003001
erelongInfo.RPCTimeout = params.RPCTimeout
erelongInfo.ErrorPtr = &err
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s",
*erelongInfo.ErrorPtr, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName)
err = errors.WithMessage(ecode.FansMedalFrameWorkGoRoutingError, "GET SEA PATROL FAIL")
return nil, err
}
// 整理数据
for _, chunkItemList := range chunkResult {
for _, item := range chunkItemList {
fansResult[item] = true
}
}
return
}
// GetGrayRule ...
// 获取灰度规则信息
func (s *IndexService) GetGrayRule(ctx context.Context, req *userExV1.GrayRuleGetByMarkReq) (extResult *userExV1.GrayRuleGetByMarkResp_Data, err error) {
extResult = &userExV1.GrayRuleGetByMarkResp_Data{}
if req == nil {
return nil, nil
}
ret, err := s.userextDao.GetGrayRule(ctx, req)
if err != nil {
log.Error("call_userExt_grayRule error,err:%v", err)
err = errors.WithMessage(ecode.GetGrayRuleError, "GET SEA PATROL FAIL")
return
}
extResult = ret.Data
return
}
// GetGiftInfo ...
// 获取送礼信息
func GetGiftInfo(ctx context.Context) (giftInfo map[int64]int64, err error) {
relationParams := &relationV1.BaseInfoGetGiftInfoReq{}
giftInfo = make(map[int64]int64)
ret, err := dao.RelationApi.V1BaseInfo.GetGiftInfo(ctx, relationParams)
for _, v := range ret.Data {
giftInfo[v.Mid] = v.Gold
}
return
}
// GetUserInfo 获取用户信息
func (s *IndexService) GetUserInfo(ctx context.Context, UIDs []int64) (userResult map[int64]*accountM.Card, err error) {
rpcChunkSize, RPCTimeout, err := relationT.GetChunkInfo(ServiceConf.AccountGRPC)
params := ServiceConf.ChunkCallInfo{ParamsName: "uids", URLName: ServiceConf.AccountGRPC, ChunkSize: rpcChunkSize, RPCTimeout: RPCTimeout}
userResult = make(map[int64]*accountM.Card)
lens := len(UIDs)
if lens <= 0 {
return
}
// 批次
params.ChunkNum = int64(math.Ceil(float64(lens) / float64(params.ChunkSize)))
chunkResult := make([]map[int64]*accountM.Card, params.ChunkNum)
wg, _ := errgroup.WithContext(ctx)
for i := int64(1); i <= params.ChunkNum; i++ {
x := i
wg.Go(func() error {
chunkUfosIds := make([]int64, 20)
if x == params.ChunkNum {
chunkUfosIds = UIDs[(x-1)*params.ChunkSize:]
} else {
chunkUfosIds = UIDs[(x-1)*params.ChunkSize : x*params.ChunkSize]
}
ret, err := s.accountDao.GetUserInfoData(ctx, chunkUfosIds)
if err != nil {
err = errors.WithMessage(ecode.AccountGRPCError, "GET SEA PATROL FAIL")
log.Error("Call main.Account.Cards Error.Infos(%+v) error(%+v)", chunkUfosIds, err)
return nil
}
chunkResult[x-1] = ret
return nil
})
}
if err := wg.Wait(); err != nil {
erelongInfo := relationT.ErrLogStrut{}
erelongInfo.ErrType = "GoRoutingWaitError"
erelongInfo.URLName = relationT.AccountGRPC
erelongInfo.ErrDesc = relationT.GoRoutingErr
erelongInfo.Code = 1003001
erelongInfo.RPCTimeout = params.RPCTimeout
erelongInfo.ErrorPtr = &err
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s",
*erelongInfo.ErrorPtr, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName)
err = errors.WithMessage(ecode.AccountGRPCFrameError, "GET SEA PATROL FAIL")
return nil, err
}
for _, chunkItemList := range chunkResult {
for _, item := range chunkItemList {
if item != nil {
userResult[item.Mid] = item
}
}
}
return
}
// GetLiveUserExp 获取用户经验信息
func (s *IndexService) GetLiveUserExp(ctx context.Context, UIDs []int64) (userResult map[int64]*liveUserExpM.LevelInfo, err error) {
rpcChunkSize, RPCTimeout, err := relationT.GetChunkInfo(ServiceConf.LiveUserExpGRPC)
params := ServiceConf.ChunkCallInfo{ParamsName: "uids", URLName: ServiceConf.LiveUserExpGRPC, ChunkSize: rpcChunkSize, RPCTimeout: RPCTimeout}
userResult = make(map[int64]*liveUserExpM.LevelInfo)
lens := len(UIDs)
if lens <= 0 {
return
}
// 批次
params.ChunkNum = int64(math.Ceil(float64(lens) / float64(params.ChunkSize)))
chunkResult := make([]map[int64]*liveUserExpM.LevelInfo, params.ChunkNum)
wg, _ := errgroup.WithContext(ctx)
for i := int64(1); i <= params.ChunkNum; i++ {
x := i
wg.Go(func() error {
chunkUfosIds := make([]int64, 20)
if x == params.ChunkNum {
chunkUfosIds = UIDs[(x-1)*params.ChunkSize:]
} else {
chunkUfosIds = UIDs[(x-1)*params.ChunkSize : x*params.ChunkSize]
}
ret, err := s.xuserDao.GetUserExpData(ctx, chunkUfosIds)
if err != nil {
err = errors.WithMessage(ecode.AccountGRPCError, "GET SEA PATROL FAIL")
log.Error("Call main.Account.Cards Error.Infos(%+v) error(%+v)", chunkUfosIds, err)
return nil
}
chunkResult[x-1] = ret
return nil
})
}
if err := wg.Wait(); err != nil {
erelongInfo := relationT.ErrLogStrut{}
erelongInfo.ErrType = "GoRoutingWaitError"
erelongInfo.URLName = relationT.LiveUserExpGRPC
erelongInfo.ErrDesc = relationT.GoRoutingErr
erelongInfo.Code = 1003001
erelongInfo.RPCTimeout = params.RPCTimeout
erelongInfo.ErrorPtr = &err
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s",
*erelongInfo.ErrorPtr, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName)
err = errors.WithMessage(ecode.AccountGRPCFrameError, "GET SEA PATROL FAIL")
return nil, err
}
for _, chunkItemList := range chunkResult {
for _, item := range chunkItemList {
if item != nil {
userResult[item.Uid] = item
}
}
}
return
}

View File

@ -0,0 +1,532 @@
package v2
import (
"context"
"sync/atomic"
"time"
"go-common/app/interface/live/app-interface/dao/account"
"go-common/app/interface/live/app-interface/dao/av"
"go-common/app/interface/live/app-interface/dao/fans_medal"
"go-common/app/interface/live/app-interface/dao/live_data"
"go-common/app/interface/live/app-interface/dao/rankdb"
"go-common/app/interface/live/app-interface/dao/relation"
"go-common/app/interface/live/app-interface/dao/room_ex"
"go-common/app/interface/live/app-interface/dao/user_ext"
v2pb "go-common/app/interface/live/app-interface/api/http/v2"
"go-common/app/interface/live/app-interface/conf"
"go-common/app/interface/live/app-interface/dao"
liveuserDao "go-common/app/interface/live/app-interface/dao/live_user"
roomDao "go-common/app/interface/live/app-interface/dao/room"
roomexDao "go-common/app/interface/live/app-interface/dao/room_ex"
xuserDao "go-common/app/interface/live/app-interface/dao/xuser"
liveUserV1 "go-common/app/service/live/live_user/api/liverpc/v1"
recommendV1 "go-common/app/service/live/recommend/api/grpc/v1"
roomV2 "go-common/app/service/live/room/api/liverpc/v2"
xrf "go-common/app/service/live/xroom-feed/api"
"go-common/library/log"
"go-common/library/net/http/blademaster"
"go-common/library/net/metadata"
"go-common/library/sync/errgroup"
"go-common/library/xstr"
)
const (
_bannerType = 1
_entranceType = 2
_yunyingRecFormType = 3
_yunyingRecSquareType = 4
_rankType = 5
_recFormType = 6
_recSquareType = 7
_feedType = 8
_parentAreaFormType = 9
_parentAreaSquareType = 10
_activityType = 11
_myAreaTagType = 12
_myAreaTagListType = 13
_seaPatrolType = 14
)
// IndexService struct
type IndexService struct {
conf *conf.Config
commonType []int64
// dao
dao *dao.Dao
roomDao *roomDao.Dao
liveuserDao *liveuserDao.Dao
rankdbDao *rankdb.Dao
livedataDao *live_data.Dao
relationDao *relation.Dao
roomexDao *room_ex.Dao
userextDao *user_ext.Dao
avDao *av.Dao
fansMedalDao *fans_medal.Dao
accountDao *account.Dao
xuserDao *xuserDao.Dao
// cache
// all base module cache
//AllMInfoMap map[int64][]*v2pb.ModuleInfo
AllMInfoMap atomic.Value
//areaEntranceMap map[int64][]*v2pb.PicItem
areaEntranceListMap atomic.Value
commonRoomList atomic.Value
recommendConn recommendV1.RecommendClient
xrfClient *xrf.Client
}
// NewIndexService init
func NewIndexService(c *conf.Config) (s *IndexService) {
s = &IndexService{
conf: c,
dao: dao.New(c),
roomDao: roomDao.New(c),
liveuserDao: liveuserDao.New(c),
rankdbDao: rankdb.New(c),
roomexDao: roomexDao.New(c),
accountDao: account.New(c),
xuserDao: xuserDao.New(c),
commonType: []int64{
_yunyingRecFormType,
_yunyingRecSquareType,
_recFormType,
_recSquareType,
_parentAreaFormType,
_parentAreaSquareType,
},
}
// init cache data
s.loadAllModuleInfoMap()
s.loadAreaEntranceCache()
s.loadCommonListMap()
s.loadLastHourData(context.TODO())
go s.allModuleInfoProc()
go s.areaEntranceProc()
go s.allcommonListProc()
go s.loadLastHour()
conn, err := recommendV1.NewClient(conf.Conf.Warden)
if err != nil {
panic(err)
}
s.recommendConn = conn
xrfc, err := xrf.NewClient(conf.Conf.Warden)
if err != nil {
panic(err)
}
s.xrfClient = xrfc
return s
}
// Index 相关服务
// GetAllList implementation
// 首页大接口
// `midware:"guest,verify"`
func (s *IndexService) GetAllList(ctx context.Context, req *v2pb.GetAllListReq) (resp *v2pb.GetAllListResp, err error) {
resp = &v2pb.GetAllListResp{
Interval: 10,
IsSkyHorseGray: 0,
Banner: []*v2pb.MBanner{},
MyTag: []*v2pb.MMyTag{},
AreaEntrance: []*v2pb.MAreaEntrance{},
SeaPatrol: []*v2pb.MSeaPatrol{},
MyIdol: []*v2pb.MMyIdol{},
RoomList: []*v2pb.MRoomBlock{},
HourRank: []*v2pb.MHourRank{},
ActivityCard: []*v2pb.MActivityCard{},
}
moduleInfoMap := s.GetAllModuleInfoMapFromCache(ctx)
if moduleInfoMap == nil {
log.Error("[GetAllList]module info list is nil, moduleIds:%+v", moduleInfoMap)
return
}
// 初始化各模块返回信息
respCommonRoomList := make([]*v2pb.MRoomBlock, 0)
respMultiRoomList := make([]*v2pb.MRoomBlock, 0)
myAreaMap := make(map[int64]bool)
respMyIdol := &v2pb.MMyIdol{}
respSkyHorseRoomList := make([]*v2pb.CommonRoomItem, 0)
respLiveRecRoomList := make([]*v2pb.CommonRoomItem, 0)
// 大多使用header里的mid解析, 框架已封装请求的header
midInterface, isUIDSet := metadata.Value(ctx, metadata.Mid).(int64)
mid := int64(0)
if isUIDSet {
mid = midInterface
}
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
}
// 第一波并发获取数据,无依赖
func(device *blademaster.Device) {
wg1 := errgroup.Group{}
// banner
if s.isModuleExist(_bannerType) {
wg1.Go(func() (err error) {
resp.Banner = s.getIndexBanner(ctx, req.Platform, req.Device, req.Build)
return
})
}
// 常用标签列表
if s.isModuleExist(_myAreaTagType) {
wg1.Go(func() (err error) {
resp.MyTag, _ = s.GetIndexV2TagList(ctx, &liveUserV1.UserSettingGetTagReq{})
return
})
}
// 分区入口
if s.isModuleExist(_entranceType) {
wg1.Go(func() (err error) {
resp.AreaEntrance = s.getAreaEntrance(ctx)
return
})
}
// 我的关注
if s.isModuleExist(_feedType) {
wg1.Go(func() (err error) {
resp.MyIdol = s.LiveAnchorHomePage(ctx, req.RelationPage, req.Build, req.Platform, req.Quality)
if len(resp.MyIdol) > 0 {
respMyIdol = resp.MyIdol[0]
}
return
})
}
// 通用房间列表(肯定是有的,此处不做判断),推荐、运营推荐分区、常用分区(特殊:要在第二波拿)、一级分区
wg1.Go(func() (err error) {
respCommonRoomList = s.getCommonRoomListForIndex(ctx, req.Build, req.Platform, req.Quality)
return
})
// 活动卡片
if s.isModuleExist(_activityType) {
wg1.Go(func() (err error) {
resp.ActivityCard = s.getActivityCard(ctx)
return
})
}
// 小时榜
if s.isModuleExist(_rankType) {
wg1.Go(func() (err error) {
resp.HourRank, _ = s.getLastHourTop3(ctx)
return
})
}
// 大航海
mobiApp := device.RawMobiApp
if s.isModuleExist(_seaPatrolType) && mobiApp != "iphone_b" && mobiApp != "android_b" {
wg1.Go(func() (err error) {
resp.SeaPatrol, _ = s.GetIndexV2SeaPatrol(ctx, &liveUserV1.NoteGetReq{})
return
})
}
err1 := wg1.Wait()
if err1 != nil {
log.Error("[GetAllList]wg1 wait error: %+v", err1)
}
}(device)
// 第二波获取数据 (依赖第一波)
func() {
wg2 := errgroup.Group{}
// 天马个性化推荐 无法缓存 依赖关注
if s.ifHitSkyHorse(mid, req.Device) {
wg2.Go(func() (err error) {
//目前只对第一个关注模块去重
respSkyHorseRoomList, err = s.getSkyHorseRoomListForIndex(ctx, respMyIdol, mid, buvid, req.Build, req.Platform, req.RecPage, req.Quality)
return
})
}
// 直播个性化推荐 无法缓存 依赖关注
if s.ifHitLiveRec(mid, req.Device) {
wg2.Go(func() (err error) {
respLiveRecRoomList, err = s.getLiveRecRoomList(ctx, respMyIdol, mid, req.Build, req.Platform, req.RecPage, req.Quality)
return
})
}
// 常用标签房间列表
wg2.Go(func() (err error) {
respMultiRoomList, myAreaMap = s.getMultiRoomList(ctx, resp.MyTag, req.Platform, req.Build, req.Quality)
resp.RoomList = append(resp.RoomList, respMultiRoomList...)
return
})
// 对保底逻辑的一些处理,对关注去重, 数量限制, 获取投放系统数据
wg2.Go(func() (err error) {
respCommonRoomList = s.handleCommonRoomList(ctx, respMyIdol, respCommonRoomList, req.Quality, req.Build, req.Platform, req.Device)
return
})
err2 := wg2.Wait()
if err2 != nil {
log.Error("[GetAllList]wg2 wait error: %+v", err2)
}
}()
// 推荐直播最终处理
handleRecResult(resp, respCommonRoomList, respSkyHorseRoomList, respLiveRecRoomList, myAreaMap)
if resp.IsSkyHorseGray == 0 && s.ifHitLiveRec(mid, req.Device) {
log.Info("live rec hit miss, mid:%d, liveRec:%+v", mid, respLiveRecRoomList)
}
return
}
// Change implementation
// 换一换接口
// `midware:"guest,verify"`
func (s *IndexService) Change(ctx context.Context, req *v2pb.ChangeReq) (resp *v2pb.ChangeResp, err error) {
resp = &v2pb.ChangeResp{}
mid, isUIDSet := metadata.Value(ctx, metadata.Mid).(int64)
var uid int64
if isUIDSet {
uid = mid
}
duplicates, _ := xstr.SplitInts(req.AttentionRoomId)
duplicatesMap := make(map[int64]bool)
for _, roomID := range duplicates {
duplicatesMap[roomID] = true
}
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
}
moduleInfo, err := s.roomDao.GetAllModuleInfo(ctx, req.ModuleId)
if err != nil || moduleInfo[0] == nil {
log.Error("[Change]GetModuleInfoById error:%+v", err)
return
}
// 给moduleInfo赋值
resp.ModuleInfo = &v2pb.ModuleInfo{
Id: moduleInfo[0].Id,
Link: moduleInfo[0].Link,
Pic: moduleInfo[0].Pic,
Title: moduleInfo[0].Title,
Type: moduleInfo[0].Type,
Sort: moduleInfo[0].Sort,
Count: moduleInfo[0].Count,
}
resp.List = make([]*v2pb.CommonRoomItem, 0)
isDefault := true
if s.ifHitSkyHorse(uid, req.Device) {
skyHorseList, err := s.getSkyHorseRoomList(ctx, mid, buvid, req.Build, req.Platform, duplicates, req.Page, req.Quality)
if err == nil && len(skyHorseList) > 0 {
isDefault = false
resp.IsSkyHorseGray = 1
resp.List = skyHorseList
}
}
if s.ifHitLiveRec(mid, req.Device) {
respLiveRoomList, err := s.getLiveRecRoomListForChange(ctx, mid, req.Build, req.Platform, duplicates, req.Page, req.Quality)
if err == nil && len(respLiveRoomList) > 0 {
isDefault = false
resp.IsSkyHorseGray = 1
resp.List = respLiveRoomList
} else {
log.Info("live rec hit miss, from:change, mid:%d, err:%+v, liveRec:%+v", mid, err, respLiveRoomList)
}
}
if isDefault {
resp.IsSkyHorseGray = 0
respCommonRoomList, errTemp := s.getCommonRoomListByID(ctx, req.ModuleId, req.Build, req.Platform, req.Quality, req.Device, duplicates)
if errTemp != nil {
log.Error("[Change]GetModuleInfoById error:%+v", errTemp)
err = errTemp
return
}
resp.List = respCommonRoomList
}
return
}
// 指定模块是否存在
func (s *IndexService) isModuleExist(iType int64) (res bool) {
res = false
mInfoMap := s.GetAllModuleInfoMapFromCache(context.TODO())
if _, ok := mInfoMap[iType]; ok {
res = true
}
return
}
// 推荐模块最终处理:天马、对关注去重
func handleRecResult(resp *v2pb.GetAllListResp, respCommonRoomList []*v2pb.MRoomBlock, respSkyHorseRoomList []*v2pb.CommonRoomItem, respLiveRecRoomList []*v2pb.CommonRoomItem, myAreaMap map[int64]bool) {
afterHandleRoomList := make([]*v2pb.MRoomBlock, 0)
for _, roomBlock := range respCommonRoomList {
if roomBlock.ModuleInfo.Type == _recFormType || roomBlock.ModuleInfo.Type == _recSquareType {
if len(respSkyHorseRoomList) > 0 {
resp.IsSkyHorseGray = 1
roomBlock.List = respSkyHorseRoomList
} else if len(respLiveRecRoomList) > 0 {
resp.IsSkyHorseGray = 1
roomBlock.List = respLiveRecRoomList
}
afterHandleRoomList = append(afterHandleRoomList, roomBlock)
continue
}
// 常用分区对运营推荐分区去重
if roomBlock.ModuleInfo.Type == _yunyingRecFormType || roomBlock.ModuleInfo.Type == _yunyingRecSquareType {
for _, item := range roomBlock.List {
if _, ok := myAreaMap[item.AreaV2Id]; !ok {
afterHandleRoomList = append(afterHandleRoomList, roomBlock)
break
}
}
continue
}
afterHandleRoomList = append(afterHandleRoomList, roomBlock)
}
resp.RoomList = append(resp.RoomList, afterHandleRoomList...)
}
// get AllModuleInfoMap
func (s *IndexService) getAllModuleInfoMap(ctx context.Context) (allMInfoCacheMap map[int64][]*v2pb.ModuleInfo) {
var allMInfoData []*roomV2.AppIndexGetBaseMInfoListResp_ModuleInfo
var err error
var retry int64
for i := 1; i <= 3; i++ {
// 最多重试3次
allMInfoData, err = s.roomDao.GetAllModuleInfo(ctx, 0)
if err != nil || len(allMInfoData) <= 0 {
retry++
log.Error("[loadAllModuleInfoMap] GetAllModuleInfo error(%+v) retry_times(%d)", err, retry)
continue
}
break
}
if len(allMInfoData) > 0 && allMInfoData[1] != nil {
allMInfoCacheMap = make(map[int64][]*v2pb.ModuleInfo)
for _, m := range allMInfoData {
allMInfoCacheMap[m.Type] = append(allMInfoCacheMap[m.Type], &v2pb.ModuleInfo{
Id: m.Id,
Link: m.Link,
Pic: m.Pic,
Title: m.Title,
Type: m.Type,
Sort: m.Sort,
Count: m.Count,
})
}
}
return
}
// cache load
func (s *IndexService) loadAllModuleInfoMap() {
allMInfoCacheMap := s.getAllModuleInfoMap(context.TODO())
if len(allMInfoCacheMap) > 0 {
s.AllMInfoMap.Store(allMInfoCacheMap)
log.Info("[loadAllModuleInfoMap]load data success!")
}
}
// ticker
func (s *IndexService) allModuleInfoProc() {
for {
time.Sleep(time.Second * 5)
s.loadAllModuleInfoMap()
}
}
// GetAllModuleInfoMapFromCache get all module info fromcache
func (s *IndexService) GetAllModuleInfoMapFromCache(ctx context.Context) (res map[int64][]*v2pb.ModuleInfo) {
// load
i := s.AllMInfoMap.Load()
// assert
res, ok := i.(map[int64][]*v2pb.ModuleInfo)
if ok {
return
}
// 回源&log
res = s.getAllModuleInfoMap(ctx)
log.Warn("[GetAllModuleInfoMap]memory cache miss!! i:%+v; res:%+v", i, res)
return
}
func (s *IndexService) getCommonListFromCache(sIds []int64) (commonList map[int64]*roomV2.AppIndexGetRoomListByIdsResp_RoomList) {
commonListCache, ok := s.commonRoomList.Load().(map[int64]*roomV2.AppIndexGetRoomListByIdsResp_RoomList)
if ok {
commonList = commonListCache
return
}
roomListMap, err := s.roomDao.GetListByIds(context.TODO(), sIds)
if err != nil {
log.Error("[getCommonListFromCache]GetListByIds error, error:%+v", err)
return
}
commonList = roomListMap
log.Warn("[getCommonListFromCache]memory cache miss!! res:%+v", commonList)
return
}
func (s *IndexService) loadCommonListMap() {
sIds := s.getIdsFromModuleMap(context.TODO(), s.commonType)
roomListMap, err := s.roomDao.GetListByIds(context.TODO(), sIds)
if err != nil {
log.Error("[loadCommonListMap]GetListByIds error, error:%+v", err)
return
}
copyRoomListMap := make(map[int64]*roomV2.AppIndexGetRoomListByIdsResp_RoomList)
for moduleId, roomList := range roomListMap {
for _, item := range roomList.List {
if _, ok := copyRoomListMap[moduleId]; !ok {
copyRoomListMap[moduleId] = &roomV2.AppIndexGetRoomListByIdsResp_RoomList{
List: make([]*roomV2.AppIndexGetRoomListByIdsResp_RoomInfo, 0),
}
}
copyRoomListMap[moduleId].List = append(copyRoomListMap[moduleId].List, item)
}
}
s.commonRoomList.Store(copyRoomListMap)
}
func (s *IndexService) allcommonListProc() {
for {
time.Sleep(time.Second * 2)
s.loadCommonListMap()
}
}
// 根据type从模块信息map拿到模块ids列表
func (s *IndexService) getIdsFromModuleMap(ctx context.Context, iTypes []int64) (sIds []int64) {
mMap := s.GetAllModuleInfoMapFromCache(ctx)
sIds = make([]int64, 0)
for _, iType := range iTypes {
typeList, ok := mMap[iType]
if !ok {
continue
}
for _, item := range typeList {
if item != nil {
sIds = append(sIds, item.Id)
}
}
}
return
}

View File

@ -0,0 +1,89 @@
package v2
import (
"context"
v2pb "go-common/app/interface/live/app-interface/api/http/v2"
recommendV1 "go-common/app/service/live/recommend/api/grpc/v1"
"go-common/library/log"
)
const (
_recTypeRecommend = 5
_recNum = 6 //获取推荐的数量
)
func (s *IndexService) getLiveRecRoomList(ctx context.Context, respMyIdol *v2pb.MMyIdol, mid int64, build int64, platform string, recPage int64, quality int64) (respLiuGangRecRoomList []*v2pb.CommonRoomItem, err error) {
duplicate := make([]int64, 0)
// ctx可以换带cancel或timeout的
for _, idol := range respMyIdol.List {
duplicate = append(duplicate, idol.Roomid)
}
return s.getRecInfo(ctx, mid, duplicate, build, platform, recPage, quality)
}
func (s *IndexService) getLiveRecRoomListForChange(ctx context.Context, mid int64, build int64, platform string, duplicate []int64, recPage int64, quality int64) (respLiuGangRecRoomList []*v2pb.CommonRoomItem, err error) {
return s.getRecInfo(ctx, mid, duplicate, build, platform, recPage, quality)
}
func (s *IndexService) getRecInfo(ctx context.Context, mid int64, duplicate []int64, build int64, platform string, recPage int64, quality int64) (respLiveRecRoomList []*v2pb.CommonRoomItem, err error) {
// 天马对关注去重
duplicates := duplicate
idolDuplicateMap := make(map[int64]bool)
for _, id := range duplicates {
if _, ok := idolDuplicateMap[id]; !ok {
idolDuplicateMap[id] = true
}
}
// 获取强推
strongRecLen := 0
//不考虑位置好的
recPool := s.getRecPoolAllPosition(ctx, nil, duplicates)
// 获取强推
if len(recPool) > 0 {
for _, strongInfo := range recPool {
if strongInfo.Roomid == 0 {
continue
}
if _, ok := idolDuplicateMap[strongInfo.Roomid]; !ok {
duplicates = append(duplicates, strongInfo.Roomid)
strongRecLen++
}
}
}
respLiveRecRoomList = make([]*v2pb.CommonRoomItem, 0)
count := _recNum - strongRecLen
if count <= 0 {
count = _recNum
}
GetRandomRecResp, err := s.recommendConn.RandomRecsByUser(ctx, &recommendV1.GetRandomRecReq{
Uid: mid,
Count: uint32(count), // 首页6个推荐
ExistIds: duplicates,
})
if err != nil {
log.Error("[GetLiveRoomList]GetLiveRecResp err, err:%+v", err)
return
}
if GetRandomRecResp == nil {
log.Error("[GetLiveRoomList]GetLiveRecResp empty err")
return
}
if len(GetRandomRecResp.RoomIds) < count {
log.Info("[GetLiveRoomList]GetLiveRecResp not enough num:%d,mid:%d", len(GetRandomRecResp.RoomIds), mid)
return
}
respLiveRecRoomList, err = s.getRecRoomList(ctx, GetRandomRecResp.RoomIds, recPool, build, platform, idolDuplicateMap, _recTypeRecommend, quality)
if err != nil {
log.Error("[GetLiveRoomList]FillLiveRecRoomList err:%+v", err)
}
return
}

View File

@ -0,0 +1,110 @@
package v2
import (
"context"
"fmt"
v2pb "go-common/app/interface/live/app-interface/api/http/v2"
liveUserDao "go-common/app/interface/live/app-interface/dao/live_user"
liveUserV1 "go-common/app/service/live/live_user/api/liverpc/v1"
"go-common/library/log"
"go-common/library/net/metadata"
)
const (
_mmtagType = 12
_mseaType = 14
)
// GetIndexV2TagList ...
// 获取APP首页 - 我的个人标签列表
func (s *IndexService) GetIndexV2TagList(ctx context.Context, req *liveUserV1.UserSettingGetTagReq) (ret []*v2pb.MMyTag, err error) {
ret = []*v2pb.MMyTag{}
ExtraInfo := &v2pb.MyTagExtra{
Offline: []*v2pb.OfflineTag{},
}
List := make([]*v2pb.MyTagItem, 0)
res := &v2pb.MMyTag{}
d := &liveUserDao.Dao{}
moduleList := s.GetAllModuleInfoMapFromCache(ctx)
module, ok := moduleList[_mmtagType]
if false == ok || 0 == len(module) {
log.Error("[GetUserTagList]AllMinfoMap is empty error:%+v, %+v", err, moduleList)
return
}
for _, v := range module {
if v.Type == _mmtagType {
var data *liveUserV1.UserSettingGetTagResp_Data
data, err = d.GetUserTagList(ctx, req)
if err != nil {
log.Error("[GetUserTagList]live_user.v1.getTag rpc error:%+v, %+v", err, data)
return
}
ExtraInfo.IsGray = data.IsGray
for _, offlineInfo := range data.Offline {
ExtraInfo.Offline = append(ExtraInfo.Offline, &v2pb.OfflineTag{Id: int64(offlineInfo.Id), AreaV2Name: offlineInfo.Name})
}
for _, tagInfo := range data.Tags {
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, tagInfo.ParentName, tagInfo.Id, tagInfo.Name)
List = append(List, &v2pb.MyTagItem{AreaV2Id: int64(tagInfo.Id), AreaV2Name: tagInfo.Name, AreaV2ParentId: int64(tagInfo.ParentId), AreaV2ParentName: tagInfo.ParentName, Link: link, Pic: tagInfo.Pic, IsAdvice: int64(tagInfo.IsAdvice)})
if len(List) >= 4 {
break
}
}
List = append(List, &v2pb.MyTagItem{AreaV2Id: 0, AreaV2Name: "全部标签", AreaV2ParentId: 0, AreaV2ParentName: "", Pic: "http://i0.hdslb.com/bfs/vc/ff03528785fc8c91491d79e440398484811d6d87.png", Link: "http://live.bilibili.com/app/mytag/", IsAdvice: 1})
res.ExtraInfo = ExtraInfo
res.List = List
res.ModuleInfo = v
}
break
}
ret = append(ret, res)
return
}
// GetIndexV2SeaPatrol ...
// 获取APP首页 - 我的大航海提示信息
func (s *IndexService) GetIndexV2SeaPatrol(ctx context.Context, req *liveUserV1.NoteGetReq) (ret []*v2pb.MSeaPatrol, err error) {
ret = []*v2pb.MSeaPatrol{}
_, isUIDSet := metadata.Value(ctx, metadata.Mid).(int64)
if !isUIDSet {
return
}
ExtraInfo := &v2pb.PicItem{}
res := &v2pb.MSeaPatrol{}
d := &liveUserDao.Dao{}
moduleList := s.GetAllModuleInfoMapFromCache(ctx)
module, ok := moduleList[_mseaType]
if false == ok || 0 == len(module) {
log.Error("[GetIndexV2SeaPatrol]AllMinfoMap is empty error:%+v, %+v", err, moduleList)
return
}
for _, v := range module {
if v.Type == _mseaType {
var data *liveUserV1.NoteGetResp_Data
data, err = d.GetDaHangHai(ctx, req)
if err != nil {
log.Error("[GetIndexV2SeaPatrol]live_user.v1.getNoteSea rpc error:%+v, %+v", err, data)
return
}
if data.Title == "" || data.Link == "" { // 返回信息为空
return
}
ExtraInfo.Title = data.Title
ExtraInfo.Pic = data.Logo
ExtraInfo.Link = data.Link
ExtraInfo.Content = data.Content
ExtraInfo.Id = 0
res.ExtraInfo = ExtraInfo
res.ModuleInfo = v
}
break
}
ret = append(ret, res)
return
}

View File

@ -0,0 +1,578 @@
package v2
import (
"context"
"math"
"strconv"
"go-common/app/service/live/third_api/bvc"
"go-common/library/sync/errgroup"
"github.com/pkg/errors"
v2pb "go-common/app/interface/live/app-interface/api/http/v2"
"go-common/app/interface/live/app-interface/conf"
"go-common/app/interface/live/app-interface/dao"
relationV1 "go-common/app/interface/live/app-interface/service/v1"
relationT "go-common/app/interface/live/app-interface/service/v1/relation"
avV1 "go-common/app/service/live/av/api/liverpc/v1"
relationRpcV1 "go-common/app/service/live/relation/api/liverpc/v1"
roomV1 "go-common/app/service/live/room/api/liverpc/v1"
accountM "go-common/app/service/main/account/model"
actmdl "go-common/app/service/main/account/model"
account "go-common/app/service/main/account/rpc/client"
"go-common/library/ecode"
"go-common/library/log"
)
// RelationService struct
type RelationService struct {
conf *conf.Config
accountRPC *account.Service3
}
const (
relationPageSize = 4
app536relationPageSize = 2
)
// CheckLiveAnchorParams ... implementation
// [app端关注首页]入参校验
func CheckLiveAnchorParams(ctx context.Context, page int64) (uid int64, relationPage int64, err error) {
mid := relationT.GetUIDFromHeader(ctx)
relationPage = page
err = nil
if mid == 0 {
err = errors.WithMessage(ecode.NeedLogIn, "GET SEA PATROL FAIL")
return
}
if page <= 0 {
err = errors.WithMessage(ecode.ResourceParamErr, "GET SEA PATROL FAIL")
return
}
return mid, relationPage, err
}
// LiveAnchorHomePage ... implementation
// [app端关注首页]正在直播接口
func (s *IndexService) LiveAnchorHomePage(ctx context.Context, relationPage int64, build int64, platform string, quality int64) (Resp []*v2pb.MMyIdol) {
List := make([]*v2pb.MyIdolItem, 0)
ExtraInfo := &v2pb.MyIdolExtra{CardType: relationT.App533CardType}
Resp = make([]*v2pb.MMyIdol, 0)
s.MakeLiveAnchorDefaultResult(Resp, ExtraInfo)
uid, relationPage, err := CheckLiveAnchorParams(ctx, relationPage)
if err != nil && uid != 0 {
log.Error("[LiveAnchorHomePage]CheckParamsError,uid:%d,relationPage:%d", uid, relationPage)
return
}
wg, _ := errgroup.WithContext(ctx)
relationInfo, groupList, mapUfos2Rolaids, mapRoomID2UID, AllRoomID, err := relationV1.GetAttentionListAndGroup(ctx)
if err != nil {
log.Error("[LiveAnchorHomePage]get_attentionList_rpc_error")
return
}
// 获取全量room信息,不过滤
roomParams := &roomV1.RoomGetStatusInfoByUidsReq{Uids: groupList["all"], FilterOffline: 0, NeedBroadcastType: 1}
// room
roomResp := make(map[int64]*roomV1.RoomGetStatusInfoByUidsResp_RoomInfo)
userResp := make(map[int64]*accountM.Card)
roomCornerResp := make(map[int64]*roomV1.RoomPendantGetPendantByIdsResp_Result)
pkResp := make(map[string]int64)
wg.Go(func() error {
roomResp, err = s.GetRoomInfo(ctx, roomParams)
return err
})
if err = wg.Wait(); nil != err {
log.Error("[LiveAnchorHomePage][first_step]get_room_rpc_error")
return
}
livingUfos := make([]int64, 0)
livingRolaids := make([]int64, 0)
livingRoomInfo := GetLivingRooms(roomResp)
// 没有人直播
if len(livingRoomInfo) == 0 {
GetLastLiveAnchorInfo(ctx, roomResp, AllRoomID, mapRoomID2UID, ExtraInfo)
moduleInfoMap := s.GetAllModuleInfoMapFromCache(ctx)
for _, m := range moduleInfoMap[_feedType] {
Resp = append(Resp, &v2pb.MMyIdol{ModuleInfo: m, List: List, ExtraInfo: ExtraInfo})
}
return
}
wgHasLive := &errgroup.Group{}
wgHasLive, _ = errgroup.WithContext(ctx)
for k, v := range livingRoomInfo {
livingUfos = append(livingUfos, k)
livingRolaids = append(livingRolaids, v.RoomId)
}
// user信息
wgHasLive.Go(func() error {
userResp, err = s.GetUserInfo(ctx, livingUfos)
return err
})
// room
roomPendentParams := &roomV1.RoomPendantGetPendantByIdsReq{Ids: livingRolaids, Type: relationT.PendentMobileBadge, Position: relationT.PendentPosition}
wgHasLive.Go(func() error {
roomCornerResp, err = s.GetRoomPendantInfo(ctx, roomPendentParams)
return err
})
// pk_id
pkParams := &avV1.PkGetPkIdsByRoomIdsReq{RoomIds: livingRolaids, Platform: platform}
wgHasLive.Go(func() error {
pkResp, err = s.GetPkID(ctx, pkParams)
return err
})
if err = wgHasLive.Wait(); nil != err {
log.Error("[LiveAnchorHomePage][second_step]room/main.account/pkID/rpc_error")
return
}
attentionRoomListPlayURLMap := dao.BvcApi.GetPlayUrlMulti(ctx, livingRolaids, 0, quality, build, platform)
// 下游数据收集完成
mapSp := make([]int64, 0)
normalSp := make([]int64, 0)
mapSp = append(mapSp, groupList["special"]...)
normalSp = append(normalSp, groupList["normal"]...)
List = AdaptLivingField(livingRoomInfo, roomCornerResp, userResp, relationInfo, pkResp, attentionRoomListPlayURLMap, mapSp, normalSp, mapUfos2Rolaids)
ExtraInfo.TotalCount = int64(len(List))
// 注释原因app536灰度策略,需要恢复2卡样式(之前在535已全量4卡,但是需求变了)产品:古月
// https://www.tapd.cn/20082211/prong/stories/view/1120082211001104459
// userExtParams := &userExV1.GrayRuleGetByMarkReq{Mark: relationT.App536GrayRule}
// grayRule, err := relationT.GetGrayRule(ctx, userExtParams)
// var UserExApp536Rule string
// if err != nil {
// log.Error("[LiveAnchorHomePage]get_GrayRule_rpc_error")
// UserExApp536Rule = ""
// } else if grayRule != nil {
// UserExApp536Rule = grayRule.Content
// }
SliceList, page := s.SliceForHomePage(List, relationPage, uid, platform)
ExtraInfo.RelationPage = page
var result v2pb.MMyIdol
result.ExtraInfo = ExtraInfo
result.List = SliceList
moduleInfoMap := s.GetAllModuleInfoMapFromCache(ctx)
for _, m := range moduleInfoMap[_feedType] {
Resp = append(Resp, &v2pb.MMyIdol{ModuleInfo: m, List: result.List, ExtraInfo: result.ExtraInfo})
}
return
}
// AdaptLivingField ... implementation
// [app端关注首页]填充数据
func AdaptLivingField(roomInfo map[int64]*roomV1.RoomGetStatusInfoByUidsResp_RoomInfo,
roomPendentInfo map[int64]*roomV1.RoomPendantGetPendantByIdsResp_Result,
userResult map[int64]*accountM.Card,
relationInfo map[int64]*relationRpcV1.BaseInfoGetFollowTypeResp_UidInfo,
pkIDInfo map[string]int64, playURLInfo map[int64]*bvc.PlayUrlItem, specialUID []int64, normalUID []int64,
mapUfos2Rolaids map[int64]int64) (resp []*v2pb.MyIdolItem) {
resp = make([]*v2pb.MyIdolItem, 0)
normalResp := make([]*v2pb.MyIdolItem, 0)
resp = make([]*v2pb.MyIdolItem, 0)
if len(specialUID) > 0 {
item := LiveFireField(roomInfo, roomPendentInfo, userResult, pkIDInfo, playURLInfo, relationInfo, specialUID, mapUfos2Rolaids)
resp = AppSortRuleOnline(item)
}
if len(normalUID) > 0 {
tempResp := LiveFireField(roomInfo, roomPendentInfo, userResult, pkIDInfo, playURLInfo, relationInfo, normalUID, mapUfos2Rolaids)
normalResp = AppSortRuleOnline(tempResp)
}
if len(normalResp) > 0 {
resp = append(resp, normalResp...)
}
return
}
// SliceForHomePage ... implementation
// app534规则 [app端关注首页]首页slice逻辑,客户端只显示偶数个数,为兼容推荐去重,当个数为3时返回2
// https://www.tapd.cn/20082211/prong/stories/view/1120082211001067961
// https://www.tapd.cn/20082211/prong/stories/view/1120082211001085685
//
// app536规则 https://www.tapd.cn/20082211/prong/stories/view/1120082211001104459
func (s *IndexService) SliceForHomePage(input []*v2pb.MyIdolItem, page int64, uid int64, platform string) (resp []*v2pb.MyIdolItem, relationPage int64) {
resp = make([]*v2pb.MyIdolItem, 0)
grayRule := s.App536ABTest(uid, platform)
relationPage = page
if len(input) <= 0 {
return
}
count := int64(len(input))
// 536规则
if grayRule == 1 {
switch count {
case 1:
{
resp = input[:]
relationPage = 1
return
}
case 2:
{
resp = input[:]
relationPage = 1
return
}
}
var pageSize int64
pageSize = page
if page < 1 {
pageSize = 1
}
start := (pageSize - 1) * app536relationPageSize
end := int64(start + app536relationPageSize)
// 正常slice
if end <= count {
resp = input[start:end]
} else {
// 回环逻辑,最后一页不足pagesize时返回第一页
relationPage = 1
startIndex := 0
var startCount int64
if count > app536relationPageSize {
startCount = app536relationPageSize
} else {
startCount = count
}
resp = input[startIndex:startCount]
}
return
}
// 536之前4卡逻辑
switch count {
case 1:
{
resp = input[:]
relationPage = 1
return
}
case 2:
{
resp = input[:]
relationPage = 1
return
}
case 3:
{
resp = input[0:2]
relationPage = 1
return
}
}
var pageSize int64
pageSize = page
if page < 1 {
pageSize = 1
}
start := (pageSize - 1) * relationPageSize
end := int64(start + relationPageSize)
if end <= count {
resp = input[start:end]
} else {
relationPage = 1
startIndex := 0
var startCount int64
if count > relationPageSize {
startCount = relationPageSize
} else {
startCount = count
}
resp = input[startIndex:startCount]
}
return
}
// LiveFireField ... implementation
// [app端关注首页]填充数据
func LiveFireField(roomInfo map[int64]*roomV1.RoomGetStatusInfoByUidsResp_RoomInfo,
roomPendentInfo map[int64]*roomV1.RoomPendantGetPendantByIdsResp_Result,
userResult map[int64]*accountM.Card,
pkIDInfo map[string]int64, playURLInfo map[int64]*bvc.PlayUrlItem,
relationInfo map[int64]*relationRpcV1.BaseInfoGetFollowTypeResp_UidInfo,
ufos []int64, mapUfos2Rolaids map[int64]int64) (resp []*v2pb.MyIdolItem) {
for _, v := range ufos {
item := v2pb.MyIdolItem{}
roomID, roomIDExist := mapUfos2Rolaids[v]
if !roomIDExist {
continue
}
roomItem := roomInfo[v]
roomPendentItem := roomPendentInfo[roomID]
userItem := userResult[v]
relationItem := relationInfo[v]
pkItem := pkIDInfo[strconv.Itoa(int(roomID))]
playURLItem := playURLInfo[roomID]
if roomItem == nil || userItem == nil || relationItem == nil {
continue
}
PlayURL := ""
PlayURL265 := ""
PlayURLAcc := make([]int64, 0)
PlayURLCur := 0
PendentRu := ""
PendentRuColor := ""
PendentRuPic := ""
if playURLItem != nil {
PlayURL = playURLItem.Url["h264"]
PlayURL265 = playURLItem.Url["h265"]
PlayURLAcc = playURLItem.AcceptQuality
PlayURLCur = int(playURLItem.CurrentQuality)
}
if roomPendentItem != nil {
PendentRu = roomPendentItem.Value
PendentRuColor = roomPendentItem.BgColor
PendentRuPic = roomPendentItem.BgPic
}
item.Roomid = roomItem.RoomId
item.Uid = roomItem.Uid
item.Uname = userItem.Name
item.Face = userItem.Face
item.Title = roomItem.Title
item.LiveTagName = roomItem.AreaV2Name
item.LiveTime = roomItem.LiveTime
item.Online = roomItem.Online
item.PlayUrl = PlayURL
item.PlayUrlH265 = PlayURL265
item.AcceptQuality = PlayURLAcc
item.CurrentQuality = int64(PlayURLCur)
item.PkId = pkItem
item.Area = roomItem.Area
item.AreaName = roomItem.AreaName
item.AreaV2Id = roomItem.AreaV2Id
item.AreaV2Name = roomItem.AreaV2Name
item.AreaV2ParentId = roomItem.AreaV2ParentId
item.AreaV2ParentName = roomItem.AreaV2ParentName
item.BroadcastType = roomItem.BroadcastType
item.Link = relationT.LiveDomain + strconv.Itoa(int(roomID)) + relationT.BoastURL + strconv.Itoa(int(item.BroadcastType))
item.OfficialVerify = int64(RoleMap(userItem.Official.Role))
item.SpecialAttention = relationItem.Special
item.PendentRu = PendentRu
item.PendentRuColor = PendentRuColor
item.PendentRuPic = PendentRuPic
if len(roomItem.CoverFromUser) == 0 {
item.Cover = roomItem.Keyframe
} else {
item.Cover = roomItem.CoverFromUser
}
resp = append(resp, &item)
}
return
}
// MakeLiveAnchorDefaultResult ...
// 正在直播默认返回
func (s *IndexService) MakeLiveAnchorDefaultResult(Resp []*v2pb.MMyIdol, ExtraInfo *v2pb.MyIdolExtra) {
if ExtraInfo != nil {
ExtraInfo.TotalCount = 0
ExtraInfo.TagsDesc = ""
ExtraInfo.UnameDesc = ""
ExtraInfo.TimeDesc = ""
// [历史原因]cardType只能为1,否则客户端报错,见 https://www.tapd.cn/20082211/prong/stories/view/1120082211001086997
ExtraInfo.CardType = 1
ExtraInfo.RelationPage = 1
}
moduleInfoMap := s.GetAllModuleInfoMapFromCache(context.TODO())
for _, m := range moduleInfoMap[_feedType] {
Resp = append(Resp, &v2pb.MMyIdol{ModuleInfo: m, List: []*v2pb.MyIdolItem{}, ExtraInfo: ExtraInfo})
}
}
// GetLivingRooms ... implementation
// [app端关注首页]获取正在直播房间
func GetLivingRooms(roomResult map[int64]*roomV1.RoomGetStatusInfoByUidsResp_RoomInfo) (liveRoom map[int64]*roomV1.RoomGetStatusInfoByUidsResp_RoomInfo) {
liveRoom = make(map[int64]*roomV1.RoomGetStatusInfoByUidsResp_RoomInfo)
if len(roomResult) == 0 {
return
}
for k, v := range roomResult {
if v.LiveStatus == relationV1.RoomStatusLive {
liveRoom[k] = v
}
}
return
}
// CheckLiveAnchorParams implementation
// 入参校验
func (s *IndexService) CheckLiveAnchorParams(ctx context.Context, req *v2pb.GetAllListReq) (uid int64, relationPage int64, err error) {
if req == nil {
err = ecode.LiveAnchorReqV2ParamsNil
return
}
uid = relationT.GetUIDFromHeader(ctx)
if uid == 0 {
err = errors.WithMessage(ecode.NeedLogIn, "GET SEA PATROL FAIL")
return
}
if req.RelationPage <= 0 {
log.Error("CallRelationLiveAnchorV2ParamsCheckError|relationPage:%d", req.RelationPage)
err = errors.WithMessage(ecode.LiveAnchorReqV2ParamsError, "GET SEA PATROL FAIL")
return
}
return
}
// GetLastLiveAnchorInfo ... implementation
// [app端关注首页]获取最新一次直播信息
func GetLastLiveAnchorInfo(ctx context.Context, roomResult map[int64]*roomV1.RoomGetStatusInfoByUidsResp_RoomInfo,
RoomIDs []int64, RoomID2UID map[int64]int64, ExtraInfo *v2pb.MyIdolExtra) (uid int64, relationPage int64, err error) {
if len(roomResult) == 0 || len(RoomIDs) == 0 || len(RoomID2UID) == 0 {
return
}
lastLiveTime, _ := relationT.GetLastLiveTime(ctx, RoomIDs)
_, _, sorted := relationV1.GetLastAnchorLiveTime(lastLiveTime)
var firstRoom int64
var firstValue int64
if sorted.Len() > 0 {
for _, v := range sorted {
firstRoom = int64(v.Key)
firstValue = int64(v.Value)
break
}
firstUID := int64(RoomID2UID[firstRoom])
tempTime := make(map[int64]int64)
if firstValue > 0 {
tempTime[firstUID] = firstValue
if roomItem, exist := roomResult[firstUID]; exist {
ExtraInfo.UnameDesc = roomItem.Uname
ExtraInfo.TagsDesc = roomItem.AreaV2Name
liveDesc, _ := relationV1.TimeLineRule(tempTime, nil)
ExtraInfo.TimeDesc = liveDesc[firstUID]
}
}
}
return
}
// GetUserInfoData ...
// 调用account grpc接口cards获取用户信息
func (s *RelationService) GetUserInfoData(ctx context.Context, UIDs []int64) (userResult map[int64]*accountM.Card, err error) {
rpcChunkSize, RPCTimeout, err := relationT.GetChunkInfo(relationT.AccountGRPC)
params := relationT.ChunkCallInfo{ParamsName: "ufos", URLName: relationT.AccountGRPC, ChunkSize: rpcChunkSize, RPCTimeout: RPCTimeout}
userResult = make(map[int64]*accountM.Card)
lens := len(UIDs)
if lens <= 0 {
return
}
// 批次
params.ChunkNum = int64(math.Ceil(float64(lens) / float64(params.ChunkSize)))
chunkResult := make([]map[int64]*accountM.Card, params.ChunkNum)
wg, _ := errgroup.WithContext(ctx)
for i := int64(1); i <= params.ChunkNum; i++ {
x := i
wg.Go(func() error {
chunkUfosIds := make([]int64, 20)
if x == params.ChunkNum {
chunkUfosIds = UIDs[(x-1)*params.ChunkSize:]
} else {
chunkUfosIds = UIDs[(x-1)*params.ChunkSize : x*params.ChunkSize]
}
ret, err := s.accountRPC.Cards3(ctx, &actmdl.ArgMids{Mids: chunkUfosIds})
if err != nil {
err = errors.WithMessage(ecode.AccountGRPCError, "GET SEA PATROL FAIL")
log.Error("Call main.Account.Cards Error.Infos(%+v) error(%+v)", chunkUfosIds, err)
}
chunkResult[x-1] = ret
return nil
})
}
if err := wg.Wait(); err != nil {
erelongInfo := relationT.ErrLogStrut{}
erelongInfo.ErrType = "GoRoutingWaitError"
erelongInfo.URLName = relationT.AccountGRPC
erelongInfo.ErrDesc = relationT.GoRoutingErr
erelongInfo.Code = 1003001
erelongInfo.RPCTimeout = params.RPCTimeout
erelongInfo.ErrorPtr = &err
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s",
*erelongInfo.ErrorPtr, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName)
err = errors.WithMessage(ecode.AccountGRPCFrameError, "GET SEA PATROL FAIL")
return nil, err
}
// 整理数据
for _, chunkItemList := range chunkResult {
for _, item := range chunkItemList {
if item != nil {
userResult[item.Mid] = item
}
}
}
return
}
// App536ABTest ... hard code配置
// ABTest
func (s *IndexService) App536ABTest(mid int64, platform string) (grayType int64) {
// 因为ipad屏幕尺寸较大,展示2卡会影响体验,故如果是ipad客户端则使用4卡样式,产品tianyumo
if platform == "ipad" {
return 0
}
mUID := mid % 100
if mUID >= 0 && mUID <= 89 {
// 4卡
return 0
}
return 1
}
// 后台配置
// // App536ABTest ...
// // ABTest
// func (s *IndexService) App536ABTest(content string, mid int64) (grayType int64) {
// if len(content) == 0 {
// grayType = 0
// return
// }
// resultMap := make(map[string]int64)
// resultMap["app536_4card_type"] = 0
// resultMap["app536_2card_type"] = 1
// typeMap := make([]string, 0)
// mr := &[]GrayRule{}
// if err := json.Unmarshal([]byte(content), mr); err != nil {
// grayType = 0
// return
// }
// ruleArr := *mr
// scoreMap := make(map[string]int)
//
// for _, v := range ruleArr {
// scoreMap[v.Mark] = int(RParseInt(v.Value, 100))
// }
// sortedScore := SortMapByValue(scoreMap)
// scoreEnd := make([]int, 0)
// for _, v := range sortedScore {
// scoreEnd = append(scoreEnd, v.Value)
// typeMap = append(typeMap, v.Key)
// }
// score1 := scoreEnd[0]
// score2 := 100
// section1 := make(map[int]bool)
// section2 := make(map[int]bool)
// for section1Loop := 0; section1Loop < score1; section1Loop++ {
// section1[section1Loop] = true
// }
// for sectionLoop2 := score1; sectionLoop2 < score2; sectionLoop2++ {
// section2[sectionLoop2] = true
// }
// result := int(mid % 100)
// if scoreEnd[0] != 0 {
// if _, exist := section1[result]; exist {
// grayType = resultMap[typeMap[0]]
// return
// }
// }
// if scoreEnd[1] != 0 {
// if _, exist := section2[result]; exist {
// grayType = resultMap[typeMap[1]]
// return
// }
// }
// grayType = 0
// return
// }

View File

@ -0,0 +1,88 @@
package v2
import (
"context"
"time"
"go-common/library/log"
v2pb "go-common/app/interface/live/app-interface/api/http/v2"
)
// 获取分区入口
func (s *IndexService) getAreaEntrance(ctx context.Context) (res []*v2pb.MAreaEntrance) {
moduleInfoMap := s.GetAllModuleInfoMapFromCache(ctx)
listMap := s.getAreaEntranceListMapFromCache(ctx)
res = make([]*v2pb.MAreaEntrance, 0)
for _, m := range moduleInfoMap[_entranceType] {
if l, ok := listMap[m.Id]; ok {
res = append(res, &v2pb.MAreaEntrance{
ModuleInfo: m,
List: l,
})
}
}
return
}
// load from cache
func (s *IndexService) getAreaEntranceListMapFromCache(ctx context.Context) (res map[int64][]*v2pb.PicItem) {
// load
i := s.areaEntranceListMap.Load()
// assert
res, ok := i.(map[int64][]*v2pb.PicItem)
if ok {
return
}
// 回源&log
res = s.getAreaEntranceListMap(ctx)
log.Warn("[getAreaEntranceListMapFromCache]memory cache miss!! i:%+v; res:%+v", i, res)
return
}
// getAreaEntranceListMap raw
func (s *IndexService) getAreaEntranceListMap(ctx context.Context) (listMap map[int64][]*v2pb.PicItem) {
moduleIds := s.getIdsFromModuleMap(ctx, []int64{_entranceType})
if len(moduleIds) <= 0 {
return
}
areaResult, err := s.roomDao.GetAreaEntrance(ctx, moduleIds)
if err != nil {
log.Error("[loadAreaEntranceCache]roomDao.GetAreaEntrance get data error: %+v, data: %+v", err, areaResult)
return
}
if len(areaResult) > 0 {
listMap = make(map[int64][]*v2pb.PicItem)
for moduleId, i := range areaResult {
if i != nil && i.List != nil {
for _, ii := range i.List {
listMap[moduleId] = append(listMap[moduleId], &v2pb.PicItem{
Id: ii.Id,
Pic: ii.Pic,
Link: ii.Link,
Title: ii.Title,
})
}
}
}
}
return
}
// ticker
func (s *IndexService) areaEntranceProc() {
for {
time.Sleep(time.Minute * 1)
s.loadAreaEntranceCache()
}
}
func (s *IndexService) loadAreaEntranceCache() {
areaEntranceListMap := s.getAreaEntranceListMap(context.TODO())
if len(areaEntranceListMap) > 0 {
s.areaEntranceListMap.Store(areaEntranceListMap)
log.Info("[loadAreaEntranceCache]load data success!")
}
return
}

View File

@ -0,0 +1,180 @@
package v2
import (
"context"
"strconv"
"sync/atomic"
"time"
bp "go-common/app/interface/live/app-interface/api/http/v2"
"go-common/app/interface/live/app-interface/dao"
"go-common/app/service/live/room/api/liverpc/v1"
accountM "go-common/app/service/main/account/model"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
type lastHourCache struct {
Modules []*bp.MHourRank
CTime int64
}
const (
_hourRankType = 5
)
var LastHourItemCache atomic.Value
// 获取首页上小时排行榜
func (s *IndexService) getLastHourTop3(ctx context.Context) (resp []*bp.MHourRank, err error) {
moduleInfoMaps := s.GetAllModuleInfoMapFromCache(ctx)
resp = []*bp.MHourRank{}
module, ok := moduleInfoMaps[_hourRankType]
if !ok || 0 == len(module) {
return
}
cacheResp, err := getLastHour3FromCache(ctx)
if 0 != len(cacheResp) && 0 != len(cacheResp[0].List) {
resp = cacheResp
return
}
// load
resp, err = s.loadLastHourData(ctx)
return
}
func setLastHour3Cache(c context.Context, modules []*bp.MHourRank) {
cache := &lastHourCache{
Modules: modules,
CTime: time.Now().Unix(),
}
LastHourItemCache.Store(cache)
return
}
func getLastHour3FromCache(c context.Context) (resp []*bp.MHourRank, err error) {
resp = make([]*bp.MHourRank, 0)
now := time.Now().Unix()
resp = []*bp.MHourRank{}
cache, ok := LastHourItemCache.Load().(*lastHourCache)
if !ok || nil == cache {
return
}
cTime := cache.CTime
if now > (cTime + 60) {
return
}
resp = cache.Modules
return
}
// loadLastHour 定时存cache
func (s *IndexService) loadLastHour() {
for {
time.Sleep(time.Second * 20)
s.loadLastHourData(context.TODO())
}
}
// loadLastHourData 获取上小时榜数据
func (s *IndexService) loadLastHourData(ctx context.Context) (resp []*bp.MHourRank, err error) {
moduleInfoMaps := s.GetAllModuleInfoMapFromCache(ctx)
resp = []*bp.MHourRank{}
module, ok := moduleInfoMaps[_hourRankType]
if !ok || 0 == len(module) {
return
}
// extraInfo format
var nowHourName string
lastHourName := time.Now().Add(-time.Hour).Format("15")
timeNum, _ := strconv.Atoi(lastHourName)
lastHourName += ":00"
if timeNum > 9 {
nowHourName = strconv.Itoa(timeNum + 1)
} else {
nowHourName = time.Now().Format("15")
}
nowHourName += ":00"
subTitle := lastHourName + "-" + nowHourName + " 总榜排名"
list := []*bp.HourRankItem{}
roomReq := &v1.RoomGetStatusInfoByUidsReq{}
roomResp := &v1.RoomGetStatusInfoByUidsResp{}
userInfo := map[int64]*accountM.Card{}
wg := &errgroup.Group{}
// liveRpc call rankdb
uids, err := s.rankdbDao.GetLastHourTop3(ctx)
if 0 == len(uids) || nil != err {
goto formatReturn
}
wg, _ = errgroup.WithContext(ctx)
wg.Go(func() error {
// liveRpc call room
roomReq.Uids = uids
roomResp, err = dao.RoomApi.V1Room.GetStatusInfoByUids(ctx, roomReq)
return err
})
wg.Go(func() error {
// call account for UserInfo
userInfo, err = s.rankdbDao.GetUserInfoData(ctx, uids)
return err
})
if err = wg.Wait(); nil != err {
goto formatReturn
}
if 0 != roomResp.Code || 0 == len(roomResp.Data) {
log.Error("[app-interface][rankDbItem] liveRpc call room return error, code:%d, msg:%s", roomResp.Code, roomResp.Data)
goto formatReturn
}
if 0 == len(userInfo) {
log.Error("[app-interface][rankDbItem] call account return empty")
goto formatReturn
}
for k, v := range uids {
detail := &bp.HourRankItem{}
if nil != roomResp.Data[v] {
detail = &bp.HourRankItem{
Roomid: roomResp.Data[v].RoomId,
LiveStatus: roomResp.Data[v].LiveStatus,
AreaV2ParentId: roomResp.Data[v].AreaV2ParentId,
AreaV2Id: roomResp.Data[v].AreaV2Id,
AreaV2ParentName: roomResp.Data[v].AreaV2ParentName,
AreaV2Name: roomResp.Data[v].AreaV2Name,
Uname: userInfo[v].Name,
Face: userInfo[v].Face,
}
}
if nil != userInfo[v] {
detail.Uname = userInfo[v].Name
detail.Face = userInfo[v].Face
}
detail.Rank = int64(k + 1)
detail.Uid = v
list = append(list, detail)
}
// format return
formatReturn:
for _, v := range module {
if v.Type == _hourRankType {
item := &bp.MHourRank{
ModuleInfo: v,
ExtraInfo: &bp.HourRankExtra{SubTitle: subTitle},
List: list,
}
resp = append(resp, item)
break
}
}
moduleCache := resp
setLastHour3Cache(ctx, moduleCache)
return
}

View File

@ -0,0 +1,215 @@
package v2
import (
"math"
"strconv"
v2pb "go-common/app/interface/live/app-interface/api/http/v2"
"go-common/app/interface/live/app-interface/dao"
xrf "go-common/app/service/live/xroom-feed/api"
"go-common/library/sync/errgroup"
"go-common/library/xstr"
"context"
"go-common/library/log"
)
const _appModuleType = 1
// getRecPoolList
func (s *IndexService) getRecPoolList(ctx context.Context, module int64, num int64, moduleExists []int64, otherExists []int64) (list map[int64]*xrf.RoomItem) {
list = make(map[int64]*xrf.RoomItem)
req := &xrf.RecPoolReq{
ModuleType: module,
PositionNum: num,
ModuleExistRooms: xstr.JoinInts(moduleExists),
OtherExistRooms: xstr.JoinInts(otherExists),
From: "app-interface",
}
resp, ferr := s.xrfClient.RecPoolClient.GetList(ctx, req)
if ferr != nil {
log.Error("[rec_pool]GetList from xroom-feed err:%+v", ferr.Error())
return
}
list = resp.List
return
}
func (s *IndexService) getRecPoolAllPosition(ctx context.Context, moduleRoomIDs, otherRoomIDs []int64) (recPool map[int64]*v2pb.CommonRoomItem) {
recPool = make(map[int64]*v2pb.CommonRoomItem)
uids := make([]int64, 0)
roomIds := make([]int64, 0)
mapRoomIdToUid := make(map[int64]int64)
roomItem := s.getRecPoolList(ctx, _appModuleType, 6, moduleRoomIDs, otherRoomIDs)
if len(roomItem) <= 0 {
log.Info("[getRecPoolAllPosition]getRecPoolList roomItem empty")
return
}
for i, item := range roomItem {
uids = append(uids, item.Uid)
roomIds = append(roomIds, item.RoomId)
mapRoomIdToUid[item.RoomId] = item.Uid
recPool[i] = &v2pb.CommonRoomItem{
Roomid: item.RoomId,
Title: item.Title,
Link: "/" + strconv.Itoa(int(item.RoomId)),
AreaV2Id: item.AreaId,
AreaV2Name: item.AreaName,
AreaV2ParentId: item.ParentAreaId,
AreaV2ParentName: item.ParentAreaName,
Online: item.PopularityCount,
Cover: s.getCover(item.Cover, item.Keyframe),
RecType: item.RecType,
AcceptQuality: []int64{2, 4},
}
}
if len(recPool) <= 0 {
return
}
extraInfo := s.getExtraDataForRoom(ctx, roomIds, uids, mapRoomIdToUid)
for _, pool := range recPool {
if _, ok := extraInfo[pool.Roomid]; ok {
pool.Uname = extraInfo[pool.Roomid].UName
pool.Face = extraInfo[pool.Roomid].Face
pool.PendentRu = extraInfo[pool.Roomid].PendentRu
pool.PendentRuPic = extraInfo[pool.Roomid].PendentRuPic
pool.PendentRuColor = extraInfo[pool.Roomid].PendentRuColor
}
}
return
}
func (s *IndexService) handleCommonRoomList(ctx context.Context, respMyIdol *v2pb.MMyIdol, respCommonRoomList []*v2pb.MRoomBlock, quality, build int64, platform string, device string) []*v2pb.MRoomBlock {
moduleExistIds := make([]int64, 0)
otherExistIds := make([]int64, 0)
duplicateMap := make(map[int64]bool)
for _, idol := range respMyIdol.List {
otherExistIds = append(otherExistIds, idol.Roomid)
duplicateMap[idol.Roomid] = true
}
for _, roomBlock := range respCommonRoomList {
if roomBlock.ModuleInfo.Type == _recFormType || roomBlock.ModuleInfo.Type == _recSquareType {
newRecRoomList := make([]*v2pb.CommonRoomItem, 0)
for _, item := range roomBlock.List {
if len(newRecRoomList) >= 24 {
break
}
if _, ok := duplicateMap[item.Roomid]; !ok {
newRecRoomList = append(newRecRoomList, item)
moduleExistIds = append(moduleExistIds, item.Roomid)
}
}
// 投放位
if device != "pad" {
recPool, recPoolRooms := s.fourTimeRecPoolForYumo(ctx, moduleExistIds, otherExistIds)
log.Info("[handleCommonRoomList]投放位 recPool: %+v, moduleExistIds: %+v, otherExistIds:%+v", recPoolRooms, xstr.JoinInts(moduleExistIds), xstr.JoinInts(otherExistIds))
duplicateRecMap := make(map[int64]bool)
for _, id := range recPoolRooms {
duplicateRecMap[id] = true
}
newRecFilterCommonList := make([]*v2pb.CommonRoomItem, 0)
for _, room := range newRecRoomList {
if room == nil {
continue
}
if _, ok := duplicateRecMap[room.Roomid]; !ok {
newRecFilterCommonList = append(newRecFilterCommonList, room)
}
}
filterList := make([]*v2pb.CommonRoomItem, 0)
for i := 0; i < 24; i++ {
position := int64(i) + 1
if item, ok := recPool[position]; ok {
filterList = append(filterList, item)
continue
}
if len(newRecFilterCommonList) <= 0 {
continue
}
filterList = append(filterList, newRecFilterCommonList[0:1][0])
newRecFilterCommonList = newRecFilterCommonList[1:]
}
roomBlock.List = filterList
} else {
roomBlock.List = newRecRoomList
}
}
}
// 拼playurl
roomIds := make([]int64, 0)
for _, commRoomBlock := range respCommonRoomList {
for _, roomList := range commRoomBlock.List {
roomIds = append(roomIds, roomList.Roomid)
}
}
changeRoomListPlayURLMap := dao.BvcApi.GetPlayUrlMulti(ctx, roomIds, 0, quality, build, platform)
for _, v := range respCommonRoomList {
for _, vv := range v.List {
if changeRoomListPlayURLMap[vv.Roomid] != nil {
vv.AcceptQuality = changeRoomListPlayURLMap[vv.Roomid].AcceptQuality
vv.CurrentQuality = changeRoomListPlayURLMap[vv.Roomid].CurrentQuality
vv.PlayUrl = changeRoomListPlayURLMap[vv.Roomid].Url["h264"]
vv.PlayUrlH265 = changeRoomListPlayURLMap[vv.Roomid].Url["h265"]
}
}
}
return respCommonRoomList
}
// 一次请求 变为四次请求xroom feed
func (s *IndexService) fourTimeRecPoolForYumo(ctx context.Context, moduleExistIds []int64, otherExistIds []int64) (recPool map[int64]*v2pb.CommonRoomItem, recPoolRooms map[int64]int64) {
recPool = make(map[int64]*v2pb.CommonRoomItem)
recPoolRooms = make(map[int64]int64)
pageSize := 6
if len(moduleExistIds) < pageSize {
return
}
page := int64(math.Floor(float64(len(moduleExistIds)) / float64(pageSize)))
result := make([]map[int64]*v2pb.CommonRoomItem, page)
wg := errgroup.Group{}
var i int64
for i = 1; i <= page; i++ {
p := i - 1
start := p * int64(pageSize)
end := start + int64(pageSize)
duplicateIds := moduleExistIds[start:end]
wg.Go(func() (err error) {
result[p] = s.getRecPoolAllPosition(ctx, duplicateIds, otherExistIds)
return nil
})
}
err := wg.Wait()
if err != nil {
log.Error("[fourTimeRecPoolForYumo]moduleExistIds: %+v, otherExistIds:%+v", xstr.JoinInts(moduleExistIds), xstr.JoinInts(otherExistIds))
return
}
for page, recPoolMap := range result {
for position, item := range recPoolMap {
if item == nil {
continue
}
p := position + int64(page*pageSize)
recPool[p] = item
recPoolRooms[p] = item.Roomid
}
}
return
}

View File

@ -0,0 +1,43 @@
package v2
import (
"context"
"strconv"
v2pb "go-common/app/interface/live/app-interface/api/http/v2"
)
// 首页banner
func (s *IndexService) getIndexBanner(ctx context.Context, platform string, device string, build int64) (resp []*v2pb.MBanner) {
bizList := map[int64]int64{
0: _bannerType,
}
moduleList := s.GetAllModuleInfoMapFromCache(ctx)
for biz, moduleType := range bizList {
for _, moduleInfo := range moduleList[moduleType] {
bannerList, err := s.roomexDao.GetBanner(ctx, biz, 0, platform, device, build)
if err != nil {
continue
}
res := &v2pb.MBanner{}
list := make([]*v2pb.PicItem, 0)
for _, banner := range bannerList {
id, _ := strconv.Atoi(banner.Id)
list = append(list, &v2pb.PicItem{
Id: int64(id),
Link: banner.Link,
Pic: banner.Pic,
Title: banner.Title,
Content: "",
})
}
res.ModuleInfo = moduleInfo
res.List = list
resp = append(resp, res)
}
}
return
}

View File

@ -0,0 +1,307 @@
package v2
import (
"context"
"fmt"
v2pb "go-common/app/interface/live/app-interface/api/http/v2"
"go-common/app/interface/live/app-interface/dao"
roomV2 "go-common/app/service/live/room/api/liverpc/v2"
"go-common/library/log"
"go-common/library/xstr"
)
type multiModuleInfo struct {
areaName string
parentAreaId int64
areaId int64
}
const _areaModuleLink = "https://live.bilibili.com/app/area?parent_area_id=%d&parent_area_name=%s&area_id=%d&area_name=%s"
func (s *IndexService) getCommonRoomListForIndex(ctx context.Context, build int64, platform string, quality int64) (respCommonRoomList []*v2pb.MRoomBlock) {
respCommonRoomList = make([]*v2pb.MRoomBlock, 0)
moduleInfoMap := s.GetAllModuleInfoMapFromCache(ctx)
roomModuleIDs := make([]int64, 0)
for _, moduleType := range s.commonType {
if _, ok := moduleInfoMap[moduleType]; ok {
for _, moduleInfo := range moduleInfoMap[moduleType] {
respCommonRoomList = append(respCommonRoomList, &v2pb.MRoomBlock{
ModuleInfo: moduleInfo,
})
roomModuleIDs = append(roomModuleIDs, moduleInfo.Id)
}
}
}
s.getCommonRoomList(ctx, roomModuleIDs, respCommonRoomList)
return
}
func (s *IndexService) getCommonRoomList(ctx context.Context, moduleIds []int64, respCommonRoomList []*v2pb.MRoomBlock) (err error) {
if len(moduleIds) <= 0 || len(respCommonRoomList) <= 0 {
return
}
roomListMap := make(map[int64]*roomV2.AppIndexGetRoomListByIdsResp_RoomList)
roomListMap = s.getCommonListFromCache(moduleIds)
if roomListMap == nil {
log.Error("[commonList]GetListByIds error, res:%+v", roomListMap)
return
}
for _, moduleInfo := range respCommonRoomList {
moduleInfo.List = make([]*v2pb.CommonRoomItem, 0)
if _, ok := roomListMap[moduleInfo.ModuleInfo.Id]; ok {
for _, roomList := range roomListMap[moduleInfo.ModuleInfo.Id].List {
if moduleInfo.ModuleInfo.Type == _parentAreaFormType ||
moduleInfo.ModuleInfo.Type == _parentAreaSquareType ||
moduleInfo.ModuleInfo.Type == _yunyingRecSquareType ||
moduleInfo.ModuleInfo.Type == _yunyingRecFormType {
if len(moduleInfo.List) >= 4 {
break
}
}
moduleInfo.List = append(moduleInfo.List, &v2pb.CommonRoomItem{
Roomid: roomList.Roomid,
Title: roomList.Title,
Uname: roomList.Uname,
AreaV2Id: roomList.AreaV2Id,
AreaV2Name: roomList.AreaV2Name,
AreaV2ParentId: roomList.AreaV2ParentId,
AreaV2ParentName: roomList.AreaV2ParentName,
Online: roomList.Online,
Face: roomList.Face,
Cover: roomList.Cover,
BroadcastType: roomList.BroadcastType,
CurrentQuality: roomList.CurrentQuality,
AcceptQuality: roomList.AcceptQuality,
RecType: roomList.RecType,
PendentRu: roomList.PendentRu,
PendentRuColor: roomList.PendentRuColor,
PendentRuPic: roomList.PendentRuPic,
PlayUrl: roomList.PlayUrl,
PlayUrlH265: roomList.PlayUrlH265,
PkId: roomList.PkId,
})
}
}
}
return
}
func (s *IndexService) getCommonRoomListByID(ctx context.Context, moduleID int64, build int64, platform string, quality int64, device string, duplicates []int64) (respCommonRoomList []*v2pb.CommonRoomItem, err error) {
respCommonRoomList = make([]*v2pb.CommonRoomItem, 0)
duplicatesMap := make(map[int64]bool)
for _, roomID := range duplicates {
duplicatesMap[roomID] = true
}
moduleExistIds := make([]int64, 0)
if moduleID == 0 {
return
}
roomListMap, err := s.roomDao.GetListByIds(ctx, []int64{moduleID})
if err != nil {
log.Error("[commonList]GetAllModuleListByIds error, error:%+v", err)
return
}
// 24个对关注去重的item
if _, ok := roomListMap[moduleID]; ok {
list := roomListMap[moduleID].List
for _, info := range list {
if len(respCommonRoomList) >= 24 {
break
}
if _, ok := duplicatesMap[info.Roomid]; !ok {
respCommonRoomList = append(respCommonRoomList, &v2pb.CommonRoomItem{
Roomid: info.Roomid,
Title: info.Title,
Uname: info.Uname,
AreaV2Id: info.AreaV2Id,
AreaV2Name: info.AreaV2Name,
AreaV2ParentId: info.AreaV2ParentId,
AreaV2ParentName: info.AreaV2ParentName,
Online: info.Online,
Face: info.Face,
Cover: info.Cover,
BroadcastType: info.BroadcastType,
CurrentQuality: info.CurrentQuality,
AcceptQuality: info.AcceptQuality,
RecType: info.RecType,
PendentRu: info.PendentRu,
PendentRuColor: info.PendentRuColor,
PendentRuPic: info.PendentRuPic,
PlayUrl: info.PlayUrl,
PlayUrlH265: info.PlayUrlH265,
PkId: info.PkId,
})
moduleExistIds = append(moduleExistIds, info.Roomid)
}
}
filterList := make([]*v2pb.CommonRoomItem, 0)
if device != "pad" {
//投放位覆盖
recPool, recPoolRooms := s.fourTimeRecPoolForYumo(ctx, moduleExistIds, duplicates)
log.Info("[getCommonRoomListByID]投放位 recPool: %+v, moduleExistIds: %+v, otherExistIds:%+v", recPoolRooms, xstr.JoinInts(moduleExistIds), xstr.JoinInts(duplicates))
duplicateMap := make(map[int64]bool)
for _, id := range recPoolRooms {
duplicateMap[id] = true
}
newRecFilterCommonList := make([]*v2pb.CommonRoomItem, 0)
for _, room := range respCommonRoomList {
if _, ok := duplicateMap[room.Roomid]; !ok {
newRecFilterCommonList = append(newRecFilterCommonList, room)
}
}
for i := 0; i < 24; i++ {
position := int64(i) + 1
if item, ok := recPool[position]; ok {
filterList = append(filterList, item)
} else {
if len(newRecFilterCommonList) <= 0 {
continue
}
filterList = append(filterList, newRecFilterCommonList[0:1][0])
newRecFilterCommonList = newRecFilterCommonList[1:]
}
}
respCommonRoomList = filterList
}
//获取playurl
s.getPlayUrl(ctx, respCommonRoomList, quality, build, platform)
}
return
}
func (s *IndexService) getMultiRoomList(ctx context.Context, myTag []*v2pb.MMyTag, platform string, build int64, quality int64) (respMyTagRoomList []*v2pb.MRoomBlock, existAreaMap map[int64]bool) {
// 未登陆
respMyTagRoomList = make([]*v2pb.MRoomBlock, 0)
existAreaMap = make(map[int64]bool) // for duplicate yunying rec
if len(myTag) <= 0 {
log.Warn("[getMultiRoomList]my tag empty!")
return
}
parentName := map[int64]string{
1: "娱乐",
2: "游戏",
3: "手游",
4: "绘画",
5: "电台",
}
areaIds := make([]int64, 0)
multiModuleInfos := make([]*multiModuleInfo, 0)
for _, tag := range myTag {
// 默认tag没有list 跳过
if tag.ExtraInfo.IsGray == 0 {
continue
}
for _, item := range tag.List {
if item.AreaV2Id == 0 {
// 过滤异常或全部标签
continue
}
areaIds = append(areaIds, item.AreaV2Id)
multiModuleInfos = append(multiModuleInfos, &multiModuleInfo{
areaId: item.AreaV2Id,
areaName: item.AreaV2Name,
parentAreaId: item.AreaV2ParentId,
})
}
}
if len(areaIds) <= 0 {
log.Info("[getMultiRoomList]no gray tag, so no room list")
return
}
multiRoomListMap, err := s.roomDao.GetMultiRoomList(ctx, xstr.JoinInts(areaIds), platform)
if err != nil {
log.Error("[getMultiRoomList]roomDao.GetMultiRoomList get error:%+v", err)
return
}
moduleInfoMap := s.GetAllModuleInfoMapFromCache(ctx)
myTagRoomListTypeMap, exist := moduleInfoMap[_myAreaTagListType]
if !exist || myTagRoomListTypeMap == nil || len(myTagRoomListTypeMap) <= 0 {
log.Info("[getMultiRoomList]my tag room list module not exist, all: %+v", moduleInfoMap)
return
}
roomIds := make([]int64, 0)
for index, moduleInfo := range myTagRoomListTypeMap {
if len(multiModuleInfos) <= index {
// 后台多配的case防止溢出
continue
}
mInfo := multiModuleInfos[index]
if mInfo == nil {
continue
}
moduleInfo.Title = mInfo.areaName
moduleInfo.Link = fmt.Sprintf(_areaModuleLink, mInfo.parentAreaId, parentName[mInfo.parentAreaId], mInfo.areaId, mInfo.areaName)
item := &v2pb.MRoomBlock{
ModuleInfo: moduleInfo,
}
l, ok := multiRoomListMap[mInfo.areaId]
if !ok || l == nil {
continue
}
existAreaMap[mInfo.areaId] = true
innerList := make([]*v2pb.CommonRoomItem, 0)
for _, v := range l {
roomIds = append(roomIds, v.Roomid)
innerList = append(innerList, &v2pb.CommonRoomItem{
Roomid: v.Roomid,
Title: v.Title,
Uname: v.Uname,
AreaV2Id: v.AreaV2Id,
AreaV2Name: v.AreaV2Name,
AreaV2ParentId: v.AreaV2ParentId,
AreaV2ParentName: v.AreaV2ParentName,
Online: v.Online,
Face: v.Face,
Cover: v.Cover,
BroadcastType: v.BroadcastType,
CurrentQuality: v.CurrentQuality,
AcceptQuality: v.AcceptQuality,
RecType: v.RecType,
PendentRu: v.PendentRu,
PendentRuColor: v.PendentRuColor,
PendentRuPic: v.PendentRuPic,
PlayUrl: v.PlayUrl,
PlayUrlH265: v.PlayUrlH265,
PkId: v.PkId,
})
}
item.List = innerList
respMyTagRoomList = append(respMyTagRoomList, item)
}
// 拼playurl
changeRoomListPlayURLMap := dao.BvcApi.GetPlayUrlMulti(ctx, roomIds, 0, quality, build, platform)
for _, v := range respMyTagRoomList {
for _, vv := range v.List {
if changeRoomListPlayURLMap[vv.Roomid] != nil {
vv.AcceptQuality = changeRoomListPlayURLMap[vv.Roomid].AcceptQuality
vv.CurrentQuality = changeRoomListPlayURLMap[vv.Roomid].CurrentQuality
vv.PlayUrl = changeRoomListPlayURLMap[vv.Roomid].Url["h264"]
vv.PlayUrlH265 = changeRoomListPlayURLMap[vv.Roomid].Url["h265"]
}
}
}
return
}

View File

@ -0,0 +1,18 @@
package v2
import (
"flag"
"go-common/app/interface/live/app-interface/conf"
)
var (
s *IndexService
)
func init() {
flag.Set("conf", "../../cmd/test.toml")
if err := conf.Init(); err != nil {
panic(err)
}
s = NewIndexService(conf.Conf)
}

View File

@ -0,0 +1,74 @@
package v2
import (
"context"
"github.com/pkg/errors"
v2pb "go-common/app/interface/live/app-interface/api/http/v2"
"go-common/app/interface/live/app-interface/dao"
"go-common/library/ecode"
)
const (
_skyHorseRecTimeOut = 100
_recTypeForce = 3
_mobileIndexBadgeColorDefault = "#FB9E60"
_recTypeSkyHorse = 4
)
func (s *IndexService) getSkyHorseRoomListForIndex(ctx context.Context, respMyIdol *v2pb.MMyIdol, mid int64, buvid string, build int64, platform string, recPage int64, quality int64) (respSkyHorseRoomList []*v2pb.CommonRoomItem, err error) {
respSkyHorseRoomList = make([]*v2pb.CommonRoomItem, 0)
duplicate := make([]int64, 0)
// ctx可以换带cancel或timeout的
for _, idol := range respMyIdol.List {
duplicate = append(duplicate, idol.Roomid)
}
respSkyHorseRoomList, err = s.getSkyHorseRoomList(ctx, mid, buvid, build, platform, duplicate, recPage, quality)
if err != nil {
return
}
return
}
func (s *IndexService) getSkyHorseRoomList(ctx context.Context, uid int64, buvid string, build int64, platform string, idolIds []int64, recPage int64, quality int64) (respSkyHorseRoomList []*v2pb.CommonRoomItem, err error) {
// 天马对关注去重
duplicates := idolIds
idolDuplicateMap := make(map[int64]bool)
for _, id := range duplicates {
if _, ok := idolDuplicateMap[id]; !ok {
idolDuplicateMap[id] = true
}
}
strongRecLen := 0
//天马不考虑位置好的
recPool := s.getRecPoolAllPosition(ctx, nil, duplicates)
// 获取强推
if len(recPool) > 0 {
for _, strongInfo := range recPool {
if strongInfo.Roomid == 0 {
continue
}
if _, ok := idolDuplicateMap[strongInfo.Roomid]; !ok {
duplicates = append(duplicates, strongInfo.Roomid)
strongRecLen++
}
}
}
skyHorseRec, skyHorseErr := dao.SkyHorseApi.GetSkyHorseRec(ctx, uid, buvid, build, platform, duplicates, strongRecLen, _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))
}
return s.getRecRoomList(ctx, roomIds, recPool, build, platform, idolDuplicateMap, _recTypeSkyHorse, quality)
}

View File

@ -0,0 +1,208 @@
package v2
import (
"context"
"encoding/json"
"go-common/library/net/metadata"
"sort"
"strconv"
)
// Pair ...
// 自定义map排序结构
type Pair struct {
Key int64
Value int64
}
// Gray ...
// 自定义灰度策略结构
type Gray struct {
Key string
Value int
}
// GrayRule ...
// 自定义灰度策略
type GrayRule struct {
Name string `json:"name"`
Mark string `json:"mark"`
Value string `json:"value"`
}
// PairList ...
// 自定义灰度策略
type PairList []Pair
// GrayList ...
// 自定义灰度策略
type GrayList []Gray
// Swap
// 自定义排序
func (p PairList) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// Len
// 自定义排序
func (p PairList) Len() int { return len(p) }
// Less
// 自定义排序
func (p PairList) Less(i, j int) bool { return p[i].Value > p[j].Value }
// Swap
// 自定义排序
func (p GrayList) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// Len
// 自定义排序
func (p GrayList) Len() int { return len(p) }
// Less
// 自定义排序
func (p GrayList) Less(i, j int) bool { return p[i].Value < p[j].Value }
// SortMap ...
// 自定义排序
func SortMap(input map[int64]int64) (sorted PairList) {
p := make(PairList, len(input))
i := 0
for k, v := range input {
p[i] = Pair{k, v}
i++
}
sort.Sort(p)
sorted = p
return
}
// SortMapByValue ...
// 自定义排序
func SortMapByValue(m map[string]int) GrayList {
p := make(GrayList, len(m))
i := 0
for k, v := range m {
p[i] = Gray{k, v}
i++
}
sort.Sort(p)
return p
}
// RoleMap ...
// 兼容主站个人认证信息
// 见 http://info.bilibili.co/pages/viewpage.action?pageId=8742464
// 当前与客户端约定为, 0:个人 1:企业 -1:没有
func RoleMap(role int8) (changeType int64) {
switch role {
case 0:
{
changeType = -1
}
case 1, 2:
{
changeType = 0
}
case 3, 4, 5, 6:
{
changeType = 1
}
default:
{
changeType = -1
}
}
return
}
// RParseInt ...
// 转int
func RParseInt(inputStr string, defaultValue int64) (output int64) {
if mid, err := strconv.ParseInt(inputStr, 10, 64); err == nil {
output = mid
} else {
output = defaultValue
}
return
}
// App531ABTest ...
// ABTest
func (s *IndexService) App531ABTest(ctx context.Context, content string) (grayType int64) {
if len(content) == 0 {
grayType = 0
return
}
resultMap := make(map[string]int64)
resultMap["double_small_card"] = 0
resultMap["card_not_auto_play"] = 1
resultMap["card_auto_play"] = 2
typeMap := make([]string, 0)
mr := &[]GrayRule{}
if err := json.Unmarshal([]byte(content), mr); err != nil {
grayType = 0
return
}
ruleArr := *mr
scoreMap := make(map[string]int)
for _, v := range ruleArr {
scoreMap[v.Mark] = int(RParseInt(v.Value, 100))
}
sortedScore := SortMapByValue(scoreMap)
scoreEnd := make([]int, 0)
for _, v := range sortedScore {
scoreEnd = append(scoreEnd, v.Value)
typeMap = append(typeMap, v.Key)
}
score1 := scoreEnd[0]
score2 := scoreEnd[0] + scoreEnd[1]
score3 := 100
section1 := make(map[int]bool)
section2 := make(map[int]bool)
section3 := make(map[int]bool)
for section1Loop := 0; section1Loop < score1; section1Loop++ {
section1[section1Loop] = true
}
for sectionLoop2 := score1; sectionLoop2 < score2; sectionLoop2++ {
section2[sectionLoop2] = true
}
for sectionLoop3 := score2; sectionLoop3 < score3; sectionLoop3++ {
section3[sectionLoop3] = true
}
mid := GetUIDFromHeader(ctx)
result := int(mid % 100)
if scoreEnd[0] != 0 {
if _, exist := section1[result]; exist {
grayType = resultMap[typeMap[0]]
return
}
}
if scoreEnd[1] != 0 {
if _, exist := section2[result]; exist {
grayType = resultMap[typeMap[1]]
return
}
}
if scoreEnd[2] != 0 {
if _, exist := section3[result]; exist {
grayType = resultMap[typeMap[2]]
return
}
}
grayType = 0
return
}
// GetUIDFromHeader ...
// 获取uid
func GetUIDFromHeader(ctx context.Context) (uid int64) {
midInterface, isUIDSet := metadata.Value(ctx, metadata.Mid).(int64) // 大多使用header里的mid解析, 框架已封装请求的header
mid := int64(0)
if isUIDSet {
mid = midInterface
}
uid = mid
return
}