929 lines
30 KiB
Go
929 lines
30 KiB
Go
package v1
|
|
|
|
import (
|
|
"context"
|
|
"math"
|
|
"strconv"
|
|
"time"
|
|
|
|
"go-common/library/sync/errgroup"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
v1pb "go-common/app/interface/live/app-interface/api/http/v1"
|
|
"go-common/app/interface/live/app-interface/conf"
|
|
"go-common/app/interface/live/app-interface/dao"
|
|
relationT "go-common/app/interface/live/app-interface/service/v1/relation"
|
|
avV1 "go-common/app/service/live/av/api/liverpc/v1"
|
|
relationV1 "go-common/app/service/live/relation/api/liverpc/v1"
|
|
roomV1 "go-common/app/service/live/room/api/liverpc/v1"
|
|
roomExV1 "go-common/app/service/live/room_ex/api/liverpc/v1"
|
|
playurlbvc "go-common/app/service/live/third_api/bvc"
|
|
userExV1 "go-common/app/service/live/userext/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"
|
|
"go-common/library/net/rpc/liverpc"
|
|
liveConText "go-common/library/net/rpc/liverpc/context"
|
|
rpcCtx "go-common/library/net/rpc/liverpc/context"
|
|
)
|
|
|
|
// RelationService struct
|
|
type RelationService struct {
|
|
conf *conf.Config
|
|
accountRPC *account.Service3
|
|
// optionally add other properties here, such as dao
|
|
// dao *dao.Dao
|
|
}
|
|
|
|
// NewRelationService init
|
|
func NewRelationService(c *conf.Config) (s *RelationService) {
|
|
s = &RelationService{
|
|
conf: c,
|
|
accountRPC: account.New3(nil),
|
|
}
|
|
return s
|
|
}
|
|
|
|
const (
|
|
// RoomStatusLive ...
|
|
RoomStatusLive = 1
|
|
// MobileIndexBadgeColorDefault ...
|
|
MobileIndexBadgeColorDefault = "#FB9E60"
|
|
)
|
|
|
|
// UnliveAnchor ... implementation
|
|
// 直播二级页暂未开播接口
|
|
func (s *RelationService) UnliveAnchor(ctx context.Context, req *v1pb.UnLiveAnchorReq) (resp *v1pb.UnLiveAnchorResp, err error) {
|
|
resp = &v1pb.UnLiveAnchorResp{}
|
|
config := conf.GetDummyUidConf()
|
|
if config == relationT.DummyUIDEnable {
|
|
dummyHeader := &liverpc.Header{Uid: relationT.RParseInt(req.Buyaofangqizhiliao, relationT.SelfUID)}
|
|
ctx = liveConText.WithHeader(ctx, dummyHeader)
|
|
}
|
|
MakeUnLiveDefaultResult(resp)
|
|
uid := relationT.GetUIDFromHeader(ctx)
|
|
if uid <= 0 && config == 0 {
|
|
return
|
|
}
|
|
wg, _ := errgroup.WithContext(ctx)
|
|
pass, page, pageSize, uid, err := CheckUnLiveAnchorParams(ctx, req)
|
|
if !pass {
|
|
log.Error("[UnLiveAnchor]CheckParamsError,page:%d,pageSize:%d,uid:%d", page, pageSize, uid)
|
|
return
|
|
}
|
|
relationInfo, groupList, mapUfos2Rolaids, mapRolaids2Ufos, setRolaids, err := GetAttentionListAndGroup(ctx)
|
|
if err != nil {
|
|
log.Error("[LiveAnchor]get_attentionList_rpc_error")
|
|
return
|
|
}
|
|
|
|
// 获取有效(曾经直播过)主播,剪枝roomIDs
|
|
lastLiveTime, _ := relationT.GetLastLiveTime(ctx, setRolaids)
|
|
alienableRolaids, liberateInfo, sorted := FilterEverLived(lastLiveTime)
|
|
alienableUfos := GetUID(mapRolaids2Ufos, alienableRolaids)
|
|
|
|
roomExReq := &roomExV1.RoomNewsMultiGetReq{RoomIds: alienableRolaids, IsDecoded: 1}
|
|
roomParams := &roomV1.RoomGetStatusInfoByUidsReq{Uids: groupList["all"], FilterOffline: 0}
|
|
|
|
userInfo := make(map[int64]*accountM.Card)
|
|
roomResp := make(map[int64]*roomV1.RoomGetStatusInfoByUidsResp_RoomInfo)
|
|
roomExResp := make(map[int64]*roomExV1.RoomNewsMultiGetResp_Data)
|
|
userfcResp := make(map[int64]*relationV1.FeedGetUserFcBatchResp_RelationList)
|
|
|
|
// room
|
|
wg.Go(func() error {
|
|
roomResp, err = relationT.GetRoomInfo(ctx, roomParams)
|
|
return err
|
|
})
|
|
|
|
// user信息
|
|
wg.Go(func() error {
|
|
userInfo, err = s.GetUserInfoData(ctx, alienableUfos)
|
|
return err
|
|
})
|
|
|
|
// roomEx
|
|
wg.Go(func() error {
|
|
roomExResp, err = relationT.GetRoomNewsInfo(ctx, roomExReq)
|
|
return err
|
|
})
|
|
|
|
// fansNum
|
|
wg.Go(func() error {
|
|
userfcResp, err = GetUserFc(ctx, alienableUfos)
|
|
return err
|
|
})
|
|
|
|
waitErr := wg.Wait()
|
|
if waitErr != nil {
|
|
log.Error("[UnLiveAnchor][step2] rpc error: %s", waitErr)
|
|
return
|
|
}
|
|
|
|
mapSp := make(map[int64]bool)
|
|
normalSp := make(map[int64]bool)
|
|
for _, v := range groupList["special"] {
|
|
mapSp[v] = true
|
|
}
|
|
for _, v := range groupList["normal"] {
|
|
normalSp[v] = true
|
|
}
|
|
specialRoomed, normalRoomed := s.GroupByRule(ctx, mapSp, normalSp, liberateInfo, sorted, mapRolaids2Ufos)
|
|
specialUID := GetUID(mapRolaids2Ufos, specialRoomed)
|
|
normalUID := GetUID(mapRolaids2Ufos, normalRoomed)
|
|
liveDesc, newsDesc := CalcTimeLine(liberateInfo, roomExResp)
|
|
LiveCount := CountLiveRooms(roomResp)
|
|
resp.Rooms = AdaptField(roomResp, userfcResp, userInfo, roomExResp, relationInfo, specialUID, normalUID, mapUfos2Rolaids, liveDesc, newsDesc)
|
|
resp.TotalCount = int64(len(resp.Rooms))
|
|
resp.NoRoomCount = int64(len(setRolaids) - int(resp.TotalCount) - int(LiveCount))
|
|
resp.Rooms = UnLiveAnchorSlice(resp.Rooms, page, pageSize)
|
|
if (page * pageSize) >= resp.TotalCount {
|
|
resp.HasMore = 0
|
|
} else {
|
|
resp.HasMore = 1
|
|
}
|
|
return
|
|
}
|
|
|
|
// CountLiveRooms 计算正在直播数目
|
|
func CountLiveRooms(input map[int64]*roomV1.RoomGetStatusInfoByUidsResp_RoomInfo) (count int) {
|
|
if len(input) <= 0 {
|
|
count = 0
|
|
return
|
|
}
|
|
for _, v := range input {
|
|
if v.LiveStatus == RoomStatusLive {
|
|
count++
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// CheckUnLiveAnchorParams implementation
|
|
// 入参校验
|
|
func CheckUnLiveAnchorParams(ctx context.Context, req *v1pb.UnLiveAnchorReq) (pass bool, page int64, pageSize int64, uid int64, err error) {
|
|
if req == nil {
|
|
pass = false
|
|
return
|
|
}
|
|
config := conf.GetDummyUidConf()
|
|
uid = relationT.GetUIDFromHeader(ctx)
|
|
if uid == 0 && config == 0 {
|
|
err = errors.WithMessage(ecode.NeedLogIn, "GET SEA PATROL FAIL")
|
|
pass = false
|
|
return
|
|
}
|
|
page = req.Page
|
|
pageSize = req.Pagesize
|
|
if page <= 0 || pageSize <= 0 {
|
|
pass = false
|
|
log.Error("CallRelationUnLiveAnchorParamsCheckError|page:%d,pageSize:%d", page, pageSize)
|
|
err = errors.WithMessage(ecode.UnliveAnchorReqParamsError, "GET SEA PATROL FAIL")
|
|
return
|
|
}
|
|
pass = true
|
|
return
|
|
}
|
|
|
|
// CheckLiveAnchorParams implementation
|
|
// 入参校验
|
|
func CheckLiveAnchorParams(ctx context.Context, req *v1pb.LiveAnchorReq) (sortRule int64, filterRule int64, uid int64, err error) {
|
|
if req == nil {
|
|
err = ecode.LiveAnchorReqParamsNil
|
|
return
|
|
}
|
|
sortRule = req.SortRule
|
|
filterRule = req.FilterRule
|
|
uid = relationT.GetUIDFromHeader(ctx)
|
|
config := conf.GetDummyUidConf()
|
|
if uid == 0 && config == 0 {
|
|
err = errors.WithMessage(ecode.NeedLogIn, "GET SEA PATROL FAIL")
|
|
return
|
|
}
|
|
if sortRule < 0 || filterRule < 0 {
|
|
log.Error("CallRelationLiveAnchorParamsCheckError|page:%d,pageSize:%d", sortRule, filterRule)
|
|
err = errors.WithMessage(ecode.LiveAnchorReqParamsError, "GET SEA PATROL FAIL")
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// UnLiveAnchorSlice implementation
|
|
// 分页逻辑
|
|
func UnLiveAnchorSlice(req []*v1pb.UnLiveAnchorResp_Rooms, page int64, pageSize int64) (resp []*v1pb.UnLiveAnchorResp_Rooms) {
|
|
resp = make([]*v1pb.UnLiveAnchorResp_Rooms, 0)
|
|
start := (page - 1) * pageSize
|
|
end := start + pageSize
|
|
length := int64(len(req))
|
|
if start >= length {
|
|
return
|
|
}
|
|
if end >= length {
|
|
resp = req[start:]
|
|
} else {
|
|
resp = req[start:end]
|
|
}
|
|
return
|
|
}
|
|
|
|
// MakeUnLiveDefaultResult implementation
|
|
// 缺省返回
|
|
func MakeUnLiveDefaultResult(resp *v1pb.UnLiveAnchorResp) {
|
|
if resp != nil {
|
|
resp.HasMore = 0
|
|
resp.NoRoomCount = 0
|
|
resp.TotalCount = 0
|
|
resp.Rooms = make([]*v1pb.UnLiveAnchorResp_Rooms, 0)
|
|
}
|
|
}
|
|
|
|
// GroupByRule implementation
|
|
// 按照规则排序,组间按照特别关注优先,组内按照上次关播时间倒序
|
|
func (s *RelationService) GroupByRule(ctx context.Context, special map[int64]bool, normal map[int64]bool,
|
|
liberate map[int64]int64, sorted relationT.PairList, mapRolaids2Ufos map[int64]int64) (specialRoomed []int64, normalRoomed []int64) {
|
|
specialRoomed = make([]int64, 0)
|
|
normalRoomed = make([]int64, 0)
|
|
if len(liberate) == 0 || liberate == nil {
|
|
return
|
|
}
|
|
for _, v := range sorted {
|
|
if _, ok := special[mapRolaids2Ufos[v.Key]]; ok {
|
|
specialRoomed = append(specialRoomed, v.Key)
|
|
} else {
|
|
normalRoomed = append(normalRoomed, v.Key)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// AdaptField implementation
|
|
// 填充逻辑
|
|
func AdaptField(roomInfo map[int64]*roomV1.RoomGetStatusInfoByUidsResp_RoomInfo,
|
|
fansInfo map[int64]*relationV1.FeedGetUserFcBatchResp_RelationList,
|
|
userResult map[int64]*accountM.Card,
|
|
roomedInfo map[int64]*roomExV1.RoomNewsMultiGetResp_Data,
|
|
relationInfo map[int64]*relationV1.BaseInfoGetFollowTypeResp_UidInfo,
|
|
specialUID []int64, normalUID []int64,
|
|
mapUfos2Rolaids map[int64]int64, liveDesc map[int64]string, newsDesc map[int64]string) (resp []*v1pb.UnLiveAnchorResp_Rooms) {
|
|
var item []*v1pb.UnLiveAnchorResp_Rooms
|
|
resp = make([]*v1pb.UnLiveAnchorResp_Rooms, 0)
|
|
if len(specialUID) > 0 {
|
|
item = FireField(roomInfo, fansInfo, userResult, roomedInfo, relationInfo, specialUID, mapUfos2Rolaids, liveDesc, newsDesc)
|
|
resp = append(resp, item...)
|
|
}
|
|
if len(normalUID) > 0 {
|
|
item = FireField(roomInfo, fansInfo, userResult, roomedInfo, relationInfo, normalUID, mapUfos2Rolaids, liveDesc, newsDesc)
|
|
resp = append(resp, item...)
|
|
}
|
|
return
|
|
}
|
|
|
|
// CalcTimeLine ...
|
|
// 计算时间规则
|
|
func CalcTimeLine(liberateInfo map[int64]int64,
|
|
roomNewsInfo map[int64]*roomExV1.RoomNewsMultiGetResp_Data) (liveDesc map[int64]string, newsDesc map[int64]string) {
|
|
liveDesc, newsDesc = TimeLineRule(liberateInfo, roomNewsInfo)
|
|
return
|
|
}
|
|
|
|
// TimeLineRule ...
|
|
// 计算时间规则
|
|
func TimeLineRule(liberateInfo map[int64]int64, roomNewsInfo map[int64]*roomExV1.RoomNewsMultiGetResp_Data) (liveDesc map[int64]string, newsDesc map[int64]string) {
|
|
liveDesc = make(map[int64]string)
|
|
newsDesc = make(map[int64]string)
|
|
if len(liberateInfo) <= 0 {
|
|
return
|
|
}
|
|
for livedRoomed, lastLiveTime := range liberateInfo {
|
|
now := time.Now()
|
|
currentYear, currentMonth, currentDay := now.Date()
|
|
currentLocation := now.Location()
|
|
firstOfMonth := time.Date(currentYear, 1, 1, 0, 0, 0, 0, currentLocation)
|
|
thisYearUnixTimeStamp := firstOfMonth.Unix()
|
|
todayUnixTimeStamp := time.Date(currentYear, currentMonth, currentDay, 0, 0, 0, 0, currentLocation).Unix()
|
|
today24 := math.Abs(float64(todayUnixTimeStamp - lastLiveTime))
|
|
liveTime := math.Abs(float64(now.Unix() - lastLiveTime))
|
|
if lastLiveTime == 0 {
|
|
liveDesc[livedRoomed] = "上次"
|
|
}
|
|
if liveTime < 60 {
|
|
liveDesc[livedRoomed] = "刚刚"
|
|
} else if liveTime >= 60 && liveTime < 3600 {
|
|
text := int(math.Floor(liveTime / 60))
|
|
liveDesc[livedRoomed] = strconv.Itoa(text) + "分钟前"
|
|
} else if liveTime >= 3600 && liveTime < 86400 {
|
|
text := int(math.Floor(liveTime / 3600))
|
|
liveDesc[livedRoomed] = strconv.Itoa(text) + "小时前"
|
|
} else if liveTime >= 86400 && today24 <= 86400 {
|
|
liveDesc[livedRoomed] = "昨天"
|
|
} else if liveTime >= 86400 && lastLiveTime >= thisYearUnixTimeStamp {
|
|
tm := time.Unix(lastLiveTime, 0)
|
|
text := tm.Format("1-2")
|
|
liveDesc[livedRoomed] = text
|
|
} else {
|
|
if lastLiveTime < thisYearUnixTimeStamp && liveTime >= 86400 {
|
|
tm := time.Unix(lastLiveTime, 0)
|
|
text := tm.Format("2006-1-2")
|
|
liveDesc[livedRoomed] = text
|
|
} else {
|
|
tm := time.Unix(lastLiveTime, 0)
|
|
text := tm.Format("2006-1-2")
|
|
liveDesc[livedRoomed] = text
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(roomNewsInfo) <= 0 {
|
|
return
|
|
}
|
|
for livedRoomed, lastNewsTime := range roomNewsInfo {
|
|
lastLiveTimeStr := lastNewsTime.Ctime
|
|
now := time.Now()
|
|
timeFmt, _ := time.ParseInLocation("2006-01-02 15:04:05", lastLiveTimeStr, time.Local)
|
|
lastLiveTime := timeFmt.Unix()
|
|
currentYear, currentMonth, currentDay := now.Date()
|
|
currentLocation := now.Location()
|
|
todayUnixTimeStamp := time.Date(currentYear, currentMonth, currentDay, 0, 0, 0, 0, currentLocation).Unix()
|
|
today24 := math.Abs(float64(todayUnixTimeStamp - lastLiveTime))
|
|
liveTime := math.Abs(float64(now.Unix() - lastLiveTime))
|
|
if lastLiveTime == 0 {
|
|
newsDesc[livedRoomed] = ""
|
|
}
|
|
if liveTime < 60 {
|
|
newsDesc[livedRoomed] = "刚刚"
|
|
} else if liveTime >= 60 && liveTime < 3600 {
|
|
text := int(math.Floor(liveTime / 60))
|
|
newsDesc[livedRoomed] = strconv.Itoa(text) + "分钟前"
|
|
} else if liveTime >= 3600 && liveTime < 86400 {
|
|
text := int(math.Floor(liveTime / 3600))
|
|
newsDesc[livedRoomed] = strconv.Itoa(text) + "小时前"
|
|
} else if liveTime >= 86400 && today24 <= 86400 {
|
|
newsDesc[livedRoomed] = "昨天"
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// FireField ...
|
|
// 适配返回值
|
|
func FireField(roomInfo map[int64]*roomV1.RoomGetStatusInfoByUidsResp_RoomInfo,
|
|
fansInfo map[int64]*relationV1.FeedGetUserFcBatchResp_RelationList,
|
|
userResult map[int64]*accountM.Card,
|
|
roomedInfo map[int64]*roomExV1.RoomNewsMultiGetResp_Data,
|
|
relationInfo map[int64]*relationV1.BaseInfoGetFollowTypeResp_UidInfo,
|
|
ufos []int64,
|
|
mapUfos2Rolaids map[int64]int64, liveDesc map[int64]string, newsDesc map[int64]string) (resp []*v1pb.UnLiveAnchorResp_Rooms) {
|
|
for _, v := range ufos {
|
|
item := v1pb.UnLiveAnchorResp_Rooms{}
|
|
roomID, roomIDExist := mapUfos2Rolaids[v]
|
|
if !roomIDExist {
|
|
continue
|
|
}
|
|
roomItem := roomInfo[v]
|
|
userItem := userResult[v]
|
|
fansItem := fansInfo[v]
|
|
relationItem := relationInfo[v]
|
|
roomedItem := roomedInfo[roomID]
|
|
roomNewsDesc := newsDesc[roomID]
|
|
liveDescItem := liveDesc[roomID]
|
|
roomNewsContent := ""
|
|
roomNewsDescText := ""
|
|
if roomItem == nil || userItem == nil || relationItem == nil {
|
|
continue
|
|
}
|
|
if roomItem.LiveStatus == RoomStatusLive {
|
|
continue
|
|
}
|
|
if roomedItem != nil {
|
|
roomNewsContent = roomedItem.NewsContent
|
|
roomNewsDescText = roomNewsDesc
|
|
}
|
|
item.Roomid = roomItem.RoomId
|
|
item.Uid = roomItem.Uid
|
|
item.Uname = userItem.Name
|
|
item.Face = userItem.Face
|
|
item.LiveStatus = roomItem.LiveStatus
|
|
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(relationT.RoleMap(userItem.Official.Role))
|
|
item.Attentions = fansItem.Fc
|
|
item.SpecialAttention = relationItem.Special
|
|
item.AnnouncementContent = roomNewsContent
|
|
item.AnnouncementTime = roomNewsDescText
|
|
item.LiveDesc = liveDescItem
|
|
|
|
resp = append(resp, &item)
|
|
}
|
|
return
|
|
}
|
|
|
|
// LiveFireField ...
|
|
// 适配返回值
|
|
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]*playurlbvc.PlayUrlItem,
|
|
relationInfo map[int64]*relationV1.BaseInfoGetFollowTypeResp_UidInfo,
|
|
ufos []int64, mapUfos2Rolaids map[int64]int64) (resp []*v1pb.LiveAnchorResp_Rooms) {
|
|
|
|
for _, v := range ufos {
|
|
item := v1pb.LiveAnchorResp_Rooms{}
|
|
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
|
|
}
|
|
if PendentRuColor == "" {
|
|
PendentRuColor = MobileIndexBadgeColorDefault
|
|
|
|
}
|
|
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.AcceptQuality = PlayURLAcc
|
|
item.CurrentQuality = int64(PlayURLCur)
|
|
item.PkId = pkItem
|
|
item.Area = roomItem.Area
|
|
item.AreaName = roomItem.AreaName
|
|
item.AreaV2Id = roomItem.AreaV2Id
|
|
item.PlayUrlH265 = PlayURL265
|
|
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(relationT.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
|
|
}
|
|
|
|
// GroupUfos ...
|
|
// 按照关注类型分组
|
|
func GroupUfos(input map[int64]*relationV1.BaseInfoGetFollowTypeResp_UidInfo) (resp map[string][]int64, err error) {
|
|
if input == nil {
|
|
return nil, nil
|
|
}
|
|
resp = make(map[string][]int64)
|
|
for k, v := range input {
|
|
if v.Special == 0 {
|
|
resp["normal"] = append(resp["normal"], k)
|
|
} else {
|
|
resp["special"] = append(resp["special"], k)
|
|
}
|
|
resp["all"] = append(resp["all"], k)
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// GetUID ...
|
|
// 获取uid
|
|
func GetUID(idsMap map[int64]int64, input []int64) (resp []int64) {
|
|
if idsMap == nil || input == nil {
|
|
return nil
|
|
}
|
|
for _, v := range input {
|
|
resp = append(resp, idsMap[int64(v)])
|
|
}
|
|
return resp
|
|
}
|
|
|
|
// FilterEverLived ...
|
|
// 过滤未开播
|
|
func FilterEverLived(lastLiveTime map[string]string) (rolaids []int64, lifetime map[int64]int64, sorted relationT.PairList) {
|
|
rolaids = make([]int64, 0)
|
|
lifetime = make(map[int64]int64)
|
|
for roomed, v := range lastLiveTime {
|
|
timeFmt, _ := time.ParseInLocation("2006-01-02 15:04:05", v, time.Local)
|
|
if !timeFmt.IsZero() {
|
|
if mid, err := strconv.ParseInt(roomed, 10, 64); err == nil {
|
|
lifetime[mid] = timeFmt.Unix()
|
|
rolaids = append(rolaids, mid)
|
|
}
|
|
}
|
|
}
|
|
sorted = make([]relationT.Pair, 0)
|
|
sorted = relationT.SortMap(lifetime)
|
|
return rolaids, lifetime, sorted
|
|
}
|
|
|
|
// GetLastAnchorLiveTime ...
|
|
// 获取上一个主播信息
|
|
func GetLastAnchorLiveTime(lastLiveTime map[string]string) (rolaids []int64, lifetime map[int64]int64, sorted relationT.PairList) {
|
|
rolaids = make([]int64, 0)
|
|
lifetime = make(map[int64]int64)
|
|
for roomed, v := range lastLiveTime {
|
|
timeFmt, _ := time.ParseInLocation("2006-01-02 15:04:05", v, time.Local)
|
|
if mid, err := strconv.ParseInt(roomed, 10, 64); err == nil {
|
|
lifetime[mid] = timeFmt.Unix()
|
|
rolaids = append(rolaids, mid)
|
|
}
|
|
}
|
|
sorted = make([]relationT.Pair, 0)
|
|
sorted = relationT.SortMap(lifetime)
|
|
return rolaids, lifetime, sorted
|
|
}
|
|
|
|
// MakeLiveAnchorDefaultResult ...
|
|
// 正在直播默认返回
|
|
func MakeLiveAnchorDefaultResult(resp *v1pb.LiveAnchorResp) {
|
|
if resp != nil {
|
|
resp.TotalCount = 0
|
|
// [历史原因]cardType只能为1,否则客户端报错,见 https://www.tapd.cn/20082211/prong/stories/view/1120082211001086997
|
|
resp.CardType = relationT.App533CardType
|
|
resp.BigCardType = 0
|
|
resp.Rooms = make([]*v1pb.LiveAnchorResp_Rooms, 0)
|
|
}
|
|
}
|
|
|
|
// GetAttentionListAndGroup ...
|
|
// 关注分组
|
|
func GetAttentionListAndGroup(ctx context.Context) (relationInfo map[int64]*relationV1.BaseInfoGetFollowTypeResp_UidInfo, groupList map[string][]int64,
|
|
mapUfos2Rolaids map[int64]int64, mapRolaids2Ufos map[int64]int64, setRolaids []int64, attentionErr error) {
|
|
relationTimeout := conf.GetTimeout("relation", 200)
|
|
attentionErr = nil
|
|
attentionData, attentionErr := dao.RelationApi.V1BaseInfo.GetFollowType(
|
|
rpcCtx.WithTimeout(ctx, time.Duration(relationTimeout)*time.Millisecond),
|
|
&relationV1.BaseInfoGetFollowTypeReq{})
|
|
if attentionErr != nil || attentionData == nil {
|
|
attentionErr = ecode.AttentionListRPCError
|
|
return
|
|
}
|
|
relationInfo = attentionData.Data
|
|
groupList, _ = GroupUfos(attentionData.Data)
|
|
// 转换ids
|
|
mapUfos2Rolaids, err := relationT.UIDs2roomIDs(ctx, groupList["all"])
|
|
if err != nil {
|
|
attentionErr = ecode.RoomGetRoomIDCodeRPCError
|
|
return
|
|
}
|
|
mapRolaids2Ufos, setRolaids = TransRoomedUUID(mapUfos2Rolaids)
|
|
return
|
|
}
|
|
|
|
// TransRoomedUUID ...
|
|
// 转换ids
|
|
func TransRoomedUUID(mapUfos2Rolaids map[int64]int64) (mapRolaids2Ufos map[int64]int64, setRolaids []int64) {
|
|
mapRolaids2Ufos = make(map[int64]int64)
|
|
for k, v := range mapUfos2Rolaids {
|
|
mapRolaids2Ufos[v] = k
|
|
}
|
|
setRolaids = make([]int64, 0)
|
|
for _, v := range mapUfos2Rolaids {
|
|
setRolaids = append(setRolaids, v)
|
|
}
|
|
return
|
|
}
|
|
|
|
// AdaptLivingField ...
|
|
// 填充逻辑
|
|
func AdaptLivingField(roomInfo map[int64]*roomV1.RoomGetStatusInfoByUidsResp_RoomInfo,
|
|
roomPendentInfo map[int64]*roomV1.RoomPendantGetPendantByIdsResp_Result,
|
|
userResult map[int64]*accountM.Card,
|
|
relationInfo map[int64]*relationV1.BaseInfoGetFollowTypeResp_UidInfo,
|
|
pkIDInfo map[string]int64, playURLInfo map[int64]*playurlbvc.PlayUrlItem, specialUID []int64, normalUID []int64,
|
|
mapUfos2Rolaids map[int64]int64) (resp []*v1pb.LiveAnchorResp_Rooms) {
|
|
|
|
var item []*v1pb.LiveAnchorResp_Rooms
|
|
resp = make([]*v1pb.LiveAnchorResp_Rooms, 0)
|
|
normalResp := make([]*v1pb.LiveAnchorResp_Rooms, 0)
|
|
if len(specialUID) > 0 {
|
|
item = LiveFireField(roomInfo, roomPendentInfo, userResult, pkIDInfo, playURLInfo, relationInfo, specialUID, mapUfos2Rolaids)
|
|
tempResp := &v1pb.LiveAnchorResp{}
|
|
tempResp.Rooms = item
|
|
resp = relationT.AppSortRuleOnline(tempResp)
|
|
}
|
|
if len(normalUID) > 0 {
|
|
item = LiveFireField(roomInfo, roomPendentInfo, userResult, pkIDInfo, playURLInfo, relationInfo, normalUID, mapUfos2Rolaids)
|
|
tempResp := &v1pb.LiveAnchorResp{}
|
|
tempResp.Rooms = item
|
|
normalResp = relationT.AppSortRuleOnline(tempResp)
|
|
}
|
|
if len(normalResp) > 0 {
|
|
resp = append(resp, normalResp...)
|
|
}
|
|
return
|
|
}
|
|
|
|
// LiveAnchor implementation
|
|
// [app端关注二级页][全量]正在直播接口
|
|
func (s *RelationService) LiveAnchor(ctx context.Context, req *v1pb.LiveAnchorReq) (resp *v1pb.LiveAnchorResp, err error) {
|
|
resp = &v1pb.LiveAnchorResp{}
|
|
MakeLiveAnchorDefaultResult(resp)
|
|
sortRule, filterRule, uid, err := CheckLiveAnchorParams(ctx, req)
|
|
wg, _ := errgroup.WithContext(ctx)
|
|
if err != nil {
|
|
log.Error("[LiveAnchor]CheckParamsError,page:%d,pageSize:%d,uid:%d", sortRule, filterRule, uid)
|
|
return
|
|
}
|
|
relationInfo, groupList, mapUfos2Rolaids, _, _, err := GetAttentionListAndGroup(ctx)
|
|
if err != nil {
|
|
log.Error("[LiveAnchor]get_attentionList_rpc_error")
|
|
return
|
|
}
|
|
// 获取有效(正在直播中)主播,剪枝roomIDs
|
|
roomParams := &roomV1.RoomGetStatusInfoByUidsReq{Uids: groupList["all"], FilterOffline: 1, NeedBroadcastType: 1}
|
|
// room
|
|
roomResp, err := relationT.GetRoomInfo(ctx, roomParams)
|
|
if err != nil {
|
|
log.Error("[LiveAnchor]get_room_rpc_error")
|
|
return
|
|
}
|
|
livingUfos := make([]int64, 0)
|
|
livingRolaids := make([]int64, 0)
|
|
// 没有人直播
|
|
if len(roomResp) == 0 {
|
|
return
|
|
}
|
|
for k, v := range roomResp {
|
|
livingUfos = append(livingUfos, k)
|
|
livingRolaids = append(livingRolaids, v.RoomId)
|
|
}
|
|
|
|
userResp := make(map[int64]*accountM.Card)
|
|
roomCornerResp := make(map[int64]*roomV1.RoomPendantGetPendantByIdsResp_Result)
|
|
pkResp := make(map[string]int64)
|
|
attentionRoomListPlayURLMap := make(map[int64]*playurlbvc.PlayUrlItem)
|
|
build, _ := strconv.ParseInt(req.Build, 10, 64)
|
|
roomPendentParams := &roomV1.RoomPendantGetPendantByIdsReq{Ids: livingRolaids, Type: relationT.PendentMobileBadge, Position: relationT.PendentPosition}
|
|
pkParams := &avV1.PkGetPkIdsByRoomIdsReq{RoomIds: livingRolaids, Platform: req.Platform}
|
|
if err != nil {
|
|
log.Error("[LiveAnchor]get_roomPendant_rpc_error")
|
|
return
|
|
}
|
|
// user信息
|
|
wg.Go(func() error {
|
|
userResp, err = s.GetUserInfoData(ctx, livingUfos)
|
|
return err
|
|
})
|
|
// room
|
|
wg.Go(func() error {
|
|
roomCornerResp, err = relationT.GetRoomPendantInfo(ctx, roomPendentParams)
|
|
return err
|
|
})
|
|
// pk_id
|
|
wg.Go(func() error {
|
|
pkResp, err = relationT.GetPkID(ctx, pkParams)
|
|
return err
|
|
})
|
|
|
|
quality := req.Quality
|
|
if quality <= 0 {
|
|
quality = 4
|
|
}
|
|
// playurl
|
|
wg.Go(func() error {
|
|
attentionRoomListPlayURLMap = dao.BvcApi.GetPlayUrlMulti(ctx, livingRolaids, 0, quality, build, req.Platform)
|
|
return err
|
|
})
|
|
|
|
waitErr := wg.Wait()
|
|
if waitErr != nil {
|
|
log.Error("[LiveAnchor][step2] rpc error: %s", waitErr)
|
|
return
|
|
}
|
|
|
|
// 下游数据收集完成
|
|
mapSp := make([]int64, 0)
|
|
normalSp := make([]int64, 0)
|
|
mapSp = append(mapSp, groupList["special"]...)
|
|
normalSp = append(normalSp, groupList["normal"]...)
|
|
resp.Rooms = AdaptLivingField(roomResp, roomCornerResp, userResp, relationInfo, pkResp, attentionRoomListPlayURLMap, mapSp, normalSp, mapUfos2Rolaids)
|
|
resp.TotalCount = int64(len(resp.Rooms))
|
|
userExtParams := &userExV1.GrayRuleGetByMarkReq{Mark: relationT.App531GrayRule}
|
|
grayRule, err := relationT.GetGrayRule(ctx, userExtParams)
|
|
if err != nil {
|
|
log.Error("[LiveAnchor]get_GrayRule_rpc_error")
|
|
resp.BigCardType = 0
|
|
} else if grayRule != nil {
|
|
resp.BigCardType = relationT.App531ABTest(ctx, grayRule.Content, req.Build, req.Platform)
|
|
}
|
|
FilterType(ctx, livingUfos, resp, filterRule)
|
|
SortType(ctx, resp, sortRule)
|
|
return
|
|
}
|
|
|
|
// FilterType implementation
|
|
// [app端关注二级页]按照规则过滤结果集
|
|
func FilterType(ctx context.Context, targetUIDs []int64, originResult *v1pb.LiveAnchorResp, filterType int64) {
|
|
if originResult == nil || len(originResult.Rooms) == 0 {
|
|
return
|
|
}
|
|
switch filterType {
|
|
case relationT.AppFilterDefault:
|
|
{
|
|
|
|
}
|
|
case relationT.AppFilterFansMedal:
|
|
{
|
|
filteredRooms, _ := relationT.AppFilterRuleFansMedal(ctx, originResult, targetUIDs)
|
|
originResult.Rooms = filteredRooms
|
|
originResult.TotalCount = int64(len(originResult.Rooms))
|
|
}
|
|
case relationT.AppFilterGoldType:
|
|
{
|
|
filteredRooms, _ := relationT.AppFilterGold(ctx, originResult)
|
|
originResult.Rooms = filteredRooms
|
|
originResult.TotalCount = int64(len(originResult.Rooms))
|
|
}
|
|
}
|
|
}
|
|
|
|
// SortType implementation
|
|
// [app端关注二级页]按照规则排序结果集
|
|
// 规则见https://www.tapd.cn/20082211/prong/stories/view/1120082211001067961
|
|
func SortType(ctx context.Context, originResult *v1pb.LiveAnchorResp, sortType int64) (resp *v1pb.LiveAnchorResp, err error) {
|
|
if originResult == nil || len(originResult.Rooms) == 0 {
|
|
return
|
|
}
|
|
switch sortType {
|
|
// 组间特别关注、组内人气值
|
|
case relationT.AppSortDefaultT:
|
|
{
|
|
|
|
}
|
|
case relationT.AppSortRuleLiveTimeT:
|
|
{
|
|
originResult.Rooms = relationT.AppSortRuleLiveTime(originResult)
|
|
}
|
|
case relationT.AppSortRuleOnlineT:
|
|
{
|
|
originResult.Rooms = relationT.AppSortRuleOnline(originResult)
|
|
}
|
|
case relationT.AppSortRuleGoldT:
|
|
{
|
|
originResult.Rooms = relationT.AppSortRuleGold(ctx, originResult)
|
|
}
|
|
default:
|
|
}
|
|
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
|
|
}
|
|
|
|
// GetUserFc ...
|
|
// 获取用户粉丝
|
|
func GetUserFc(ctx context.Context, UIDs []int64) (userResult map[int64]*relationV1.FeedGetUserFcBatchResp_RelationList, err error) {
|
|
|
|
rpcChunkSize, RPCTimeout, err := relationT.GetChunkInfo(relationT.FansNum)
|
|
params := relationT.ChunkCallInfo{ParamsName: "ufos", URLName: relationT.FansNum, ChunkSize: rpcChunkSize, RPCTimeout: RPCTimeout}
|
|
userResult = make(map[int64]*relationV1.FeedGetUserFcBatchResp_RelationList)
|
|
lens := len(UIDs)
|
|
if lens <= 0 {
|
|
return
|
|
}
|
|
// 批次
|
|
params.ChunkNum = int64(math.Ceil(float64(lens) / float64(params.ChunkSize)))
|
|
chunkResult := make([]map[int64]*relationV1.FeedGetUserFcBatchResp_RelationList, 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 := dao.RelationApi.V1Feed.GetUserFcBatch(ctx, &relationV1.FeedGetUserFcBatchReq{Uids: 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.Data
|
|
return nil
|
|
})
|
|
}
|
|
if err := wg.Wait(); err != nil {
|
|
erelongInfo := relationT.ErrLogStrut{}
|
|
erelongInfo.ErrType = "GoRoutingWaitError"
|
|
erelongInfo.URLName = relationT.FansNum
|
|
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
|
|
}
|