You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
928 lines
30 KiB
928 lines
30 KiB
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 |
|
}
|
|
|