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,36 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["service.go"],
importpath = "go-common/app/interface/live/app-interface/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/live/app-interface/conf:go_default_library",
"//app/interface/live/app-interface/dao:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/interface/live/app-interface/service/v1:all-srcs",
"//app/interface/live/app-interface/service/v2:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,41 @@
package service
import (
"context"
"go-common/app/interface/live/app-interface/conf"
"go-common/app/interface/live/app-interface/dao"
)
// Service struct
type Service struct {
c *conf.Config
dao *dao.Dao
}
// New init
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: dao.New(c),
}
return s
}
// Ping Service
func (s *Service) Ping(c context.Context) (err error) {
return s.dao.Ping(c)
}
// Close Service
func (s *Service) Close() {
s.dao.Close()
}
// Test ...
func (s *Service) Test(c context.Context) (err error) {
// srv := &v2.IndexService{}
// res, err := srv.GetIndexV2TagList(c, &liveUserV1.UserSettingGetTagReq{})
// res, err := srv.GetIndexV2SeaPatrol(c, &liveUserV1.NoteGetReq{})
// fmt.Printf("%#v \n", res)
return
}

View File

@@ -0,0 +1,77 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"doc.go",
"index.go",
"relation.go",
],
importpath = "go-common/app/interface/live/app-interface/service/v1",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/live/app-interface/api/http/v1: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/service/v1/relation:go_default_library",
"//app/service/live/av/api/liverpc/v1:go_default_library",
"//app/service/live/live_user/api/liverpc/v1:go_default_library",
"//app/service/live/relation/api/liverpc/v1:go_default_library",
"//app/service/live/relation/api/liverpc/v2: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/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/net/rpc/liverpc:go_default_library",
"//library/net/rpc/liverpc/context:go_default_library",
"//library/sync/errgroup:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/bitly/go-simplejson: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",
"//app/interface/live/app-interface/service/v1/app_conf:all-srcs",
"//app/interface/live/app-interface/service/v1/relation:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = ["index_test.go"],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/interface/live/app-interface/api/http/v1:go_default_library",
"//app/interface/live/app-interface/conf:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,35 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["app_conf.go"],
importpath = "go-common/app/interface/live/app-interface/service/v1/app_conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/live/app-interface/api/http/v1:go_default_library",
"//app/interface/live/app-interface/conf:go_default_library",
"//app/service/live/resource/sdk:go_default_library",
"//library/ecode:go_default_library",
"//library/log: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"],
)

View File

@@ -0,0 +1,56 @@
package v1
import (
"context"
v1appconfpb "go-common/app/interface/live/app-interface/api/http/v1"
"go-common/app/interface/live/app-interface/conf"
titansSdk "go-common/app/service/live/resource/sdk"
"go-common/library/ecode"
"go-common/library/log"
)
//AppConfService struct
type AppConfService struct {
conf *conf.Config
}
// NewAppConfService init
func NewAppConfService(c *conf.Config) (s *AppConfService) {
s = &AppConfService{
conf: c,
}
InitTitan()
return s
}
//GetConf 获取移动端配置
func (s *AppConfService) GetConf(ctx context.Context, req *v1appconfpb.GetConfReq) (resp *v1appconfpb.GetConfResp, err error) {
value, ok := s.conf.AppConf[req.GetKey()]
if !ok {
log.Error("[AppConf] GetConf Key err: %s", req.GetKey())
return nil, ecode.AppConfKeyErr
}
resp = &v1appconfpb.GetConfResp{
Value: value,
}
conf, terr := titansSdk.Get(req.GetKey())
if terr != nil {
log.Error("[AppConf] GetConf titansSdk.Get err: %+v", err)
}
if conf != "" {
resp.Value = conf
}
return
}
//InitTitan 初始化kv配置
func InitTitan() {
conf := &titansSdk.Config{
TreeId: 61019,
Expire: 1,
}
titansSdk.Init(conf)
}

View File

@@ -0,0 +1,9 @@
// Copyright 2018 The BILLI Live Engineer. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package v1 为粉版App、直播App端提供卡片聚合接口,展示直播首页、关注二级页信息
// 关注模块文档 http://info.bilibili.co/display/live/APP+5.34
// 首页模块文档 http://info.bilibili.co/pages/viewpage.action?pageId=11546573
//
package v1

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,43 @@
package v1
import (
"context"
"flag"
"testing"
. "github.com/smartystreets/goconvey/convey"
api "go-common/app/interface/live/app-interface/api/http/v1"
"go-common/app/interface/live/app-interface/conf"
bm "go-common/library/net/http/blademaster"
)
var (
s *Service
)
func init() {
flag.Set("conf", "../../cmd/test.toml")
var err error
if err = conf.Init(); err != nil {
panic(err)
}
s = New(conf.Conf)
}
// go test -test.v -test.run TestGetAllList
func TestGetAllList(t *testing.T) {
Convey("TestGetAllList", t, func() {
res, err := s.GetAllList(&bm.Context{Context: context.TODO()}, &api.GetAllListReq{})
t.Logf("%v", res)
So(err, ShouldBeNil)
})
}
func TestChange(t *testing.T) {
Convey("TestChange", t, func() {
res, err := s.Change(&bm.Context{Context: context.TODO()}, &api.ChangeReq{})
t.Logf("%v", res)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,928 @@
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
}

View File

@@ -0,0 +1,64 @@
package relation
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 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 := 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 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,233 @@
package relation
import (
"context"
v1pb "go-common/app/interface/live/app-interface/api/http/v1"
"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 []*v1pb.LiveAnchorResp_Rooms
// SortOnlineTime ... implementation
// [app端关注二级页]按照开播时间排序
type SortOnlineTime []*v1pb.LiveAnchorResp_Rooms
// // AddGoldRoomInfo ... implementation
// // [app端关注二级页]按照开播时间排序
// type AddGoldRoomInfo []*LiveAnchorRespRoomsAddGold
// 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 AppSortRuleLiveTime(originResult *v1pb.LiveAnchorResp) (resp []*v1pb.LiveAnchorResp_Rooms) {
resp = make([]*v1pb.LiveAnchorResp_Rooms, 0)
if originResult == nil {
return
}
p := make(SortLiveTime, len(originResult.Rooms))
i := 0
for _, v := range originResult.Rooms {
p[i] = &v1pb.LiveAnchorResp_Rooms{
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 *v1pb.LiveAnchorResp) (resp []*v1pb.LiveAnchorResp_Rooms) {
resp = make([]*v1pb.LiveAnchorResp_Rooms, 0)
if originResult == nil {
return
}
p := make(SortOnlineTime, len(originResult.Rooms))
i := 0
for _, v := range originResult.Rooms {
p[i] = &v1pb.LiveAnchorResp_Rooms{
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,
PlayUrlH265: v.PlayUrlH265,
PendentRuPic: v.PendentRuPic}
i++
}
sort.Sort(p)
resp = p
return
}
// AppSortRuleGold implementation
// [app端关注二级页]按照送礼排序
func AppSortRuleGold(ctx context.Context, originResult *v1pb.LiveAnchorResp) (resp []*v1pb.LiveAnchorResp_Rooms) {
resp = make([]*v1pb.LiveAnchorResp_Rooms, 0)
if originResult == nil {
return
}
giftInfo, err := GetGiftInfo(ctx)
if err != nil {
log.Error("[LiveAnchor][FilterType][AppSortRuleGold]get_RelationGift_rpc_error")
resp = originResult.Rooms
return
}
if len(giftInfo) == 0 {
resp = AppSortRuleOnline(originResult)
return
}
respHasGold := make([]*v1pb.LiveAnchorResp_Rooms, 0)
respNoGold := make([]*v1pb.LiveAnchorResp_Rooms, 0)
GiftRank := make(map[int64]int64)
GiftNoGold := make([]int64, 0)
// 计算金瓜子排行榜,uid分key
for _, v := range originResult.Rooms {
roomUID := v.Uid
if _, exist := giftInfo[roomUID]; exist {
GiftRank[roomUID] += giftInfo[roomUID]
}
}
sorted := SortMap(GiftRank)
// 没有送礼的用户
for _, v := range originResult.Rooms {
if _, exist := GiftRank[v.Uid]; !exist {
GiftNoGold = append(GiftNoGold, v.Uid)
}
}
for _, vv := range sorted {
for _, v := range originResult.Rooms {
if v.Uid == vv.Key {
respHasGold = append(respHasGold, v)
}
}
}
for _, v := range originResult.Rooms {
for _, vv := range GiftNoGold {
if v.Uid == vv {
respNoGold = append(respNoGold, v)
}
}
}
tempLiveAnchor := &v1pb.LiveAnchorResp{}
tempLiveAnchor.Rooms = respNoGold
respNoGoldSorted := AppSortRuleOnline(tempLiveAnchor)
resp = append(resp, respHasGold...)
resp = append(resp, respNoGoldSorted...)
return
}

View File

@@ -0,0 +1,52 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"AppRelationFilterStrategy.go",
"AppRelationSortStrategy.go",
"Tools.go",
"rpcWraper.go",
],
importpath = "go-common/app/interface/live/app-interface/service/v1/relation",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/live/app-interface/api/http/v1:go_default_library",
"//app/interface/live/app-interface/conf:go_default_library",
"//app/interface/live/app-interface/dao: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/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/userext/api/liverpc/v1:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/metadata:go_default_library",
"//library/net/rpc/liverpc/context:go_default_library",
"//library/sync/errgroup: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"],
)

View File

@@ -0,0 +1,256 @@
package relation
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
}
// ErrLogStrut ...
// 自定义ErrLog结构
type ErrLogStrut struct {
Code int64
Msg string
ErrDesc string
ErrType string
URLName string
RPCTimeout int64
ChunkSize int64
ChunkNum int64
ErrorPtr *error
}
// 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
}
const (
_androidBugBuildLeft = 5332000
_androidBugBuildRight = 5341000
)
// 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
}
// 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
}
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
}
// CheckReturn ...
// 检查返回
func CheckReturn(err error, code int64, msg string, urlName string,
rpcTimeout int64, chunkSize int64, chunkNum int64) (errLog *ErrLogStrut, success bool) {
errInfo := ErrLogStrut{}
errInfo.URLName = urlName
errInfo.RPCTimeout = rpcTimeout
errInfo.ChunkSize = chunkSize
errInfo.ChunkNum = chunkNum
success = true
if err != nil {
errInfo.Code = 1003000
errInfo.Msg = ""
errInfo.ErrDesc = "liveRpc调用失败"
errInfo.ErrType = "LiveRpcFrameWorkCallError"
errInfo.ErrorPtr = &err
success = false
} else if code != 0 {
errInfo.Code = code
errInfo.Msg = msg
errInfo.ErrDesc = "调用直播服务" + urlName + "出错"
errInfo.ErrType = "CallLiveRpcCodeError"
success = false
}
errLog = &errInfo
return
}
// App531ABTest ...
// ABTest
func App531ABTest(ctx context.Context, content string, build string, platform string) (grayType int64) {
buildIntValue := RParseInt(build, 534000)
if platform == "android" && buildIntValue > _androidBugBuildLeft && buildIntValue <= _androidBugBuildRight {
grayType = 0
return
}
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
}

View File

@@ -0,0 +1,704 @@
package relation
import (
"context"
"math"
"strconv"
"time"
"go-common/app/interface/live/app-interface/conf"
"go-common/app/interface/live/app-interface/dao"
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"
"go-common/library/ecode"
"go-common/library/log"
rpcCtx "go-common/library/net/rpc/liverpc/context"
"go-common/library/sync/errgroup"
"github.com/pkg/errors"
)
// ChunkCallInfo ...
// 日志结构体
type ChunkCallInfo struct {
ParamsName string
URLName string
ChunkSize int64
ChunkNum int64
RPCTimeout int64
}
const (
getStatusInfoByUfos = "room/v1/Room/get_status_info_by_uids"
targetsWithMedal = "fans_medal/v1/FansMedal/targetsWithMedal"
uuid2roomed = "room/v2/Room/room_id_by_uid_multi"
record = "live_data/v1/Record/get"
getPkIdsByRoomIds = "av/v1/Pk/getPkIdsByRoomIds"
roomPendent = "room/v1/RoomPendant/getPendantByIds"
roomNews = "/room_ex/v1/RoomNews/multiGet"
relationGiftInfo = "/relation/v1/BaseInfo/getGiftInfo"
// AccountGRPC ...
// 主站grpc用户信息
AccountGRPC = "Cards3"
// LiveUserExpGRPC ...
// 直播用户经验grpc
LiveUserExpGRPC = "xuserExp"
// FansNum ...
// 直播粉丝
FansNum = "GetUserFcBatch"
// LiveDomain implementation
// 域名
LiveDomain = "http://live.bilibili.com/"
// BoastURL implementation
// 秒开url
BoastURL = "?broadcast_type="
emptyResult = "调用直播服务返回data为空"
emptyResultEn = "got_empty_result"
// GoRoutingErr ...
// 协程wait错误
GoRoutingErr = "协程等待数据错误"
// App533CardType implementation
// 大卡类型
App533CardType = 1
// PendentMobileBadge implementation
// 角标类型
PendentMobileBadge = "mobile_index_badge"
// PendentPosition implementation
// 角标位置
PendentPosition = 2
// App531GrayRule implementation
// 灰度策略
App531GrayRule = "r_big_card"
// App536GrayRule implementation
// 灰度策略
App536GrayRule = "r_homepage_card536"
// SelfUID implementation
// 调试UID
SelfUID = 22973824
// DummyUIDEnable implementation
// 调试开
DummyUIDEnable = 1
)
// UIDs2roomIDs ...
// uid转换roomID,每批最大400
func UIDs2roomIDs(ctx context.Context, ufos []int64) (rolaids map[int64]int64, err error) {
rpcChunkSize, RPCTimeout, err := GetChunkInfo(uuid2roomed)
params := ChunkCallInfo{ParamsName: "ufos", URLName: uuid2roomed, ChunkSize: rpcChunkSize, RPCTimeout: RPCTimeout}
rolaids = make(map[int64]int64)
lens := len(ufos)
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 = ufos[(x-1)*params.ChunkSize:]
} else {
chunkUfosIds = ufos[(x-1)*params.ChunkSize : x*params.ChunkSize]
}
ret, err := dao.RoomApi.V2Room.RoomIdByUidMulti(rpcCtx.WithTimeout(ctx, time.Duration(params.RPCTimeout)*time.Millisecond), &roomV2.RoomRoomIdByUidMultiReq{Uids: chunkUfosIds})
if err != nil {
ret = &roomV2.RoomRoomIdByUidMultiResp{}
ret.Code = -1
ret.Msg = "liveprc_error"
}
erelongInfo, success := CheckReturn(err, ret.Code, ret.Msg, uuid2roomed, params.RPCTimeout, params.ChunkSize, params.ChunkNum)
if !success {
if err != nil {
err = errors.WithMessage(ecode.PkIDRecordFrameWorkCallError, "GET SEA PATROL FAIL")
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s"+"|Params:%v",
err, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName, chunkUfosIds)
}
return nil
}
if ret.Data == nil || len(ret.Data) <= 0 {
erelongInfo.ErrType = emptyResultEn
erelongInfo.ErrDesc = emptyResult
// log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s"+"|Params:%v",
// erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName, chunkUfosIds)
return nil
}
chunkResult[x-1] = ret.Data
return nil
})
}
if err := wg.Wait(); err != nil {
erelongInfo := ErrLogStrut{}
erelongInfo.ErrType = "GoRoutingWaitError"
erelongInfo.URLName = uuid2roomed
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)
rolaids[Index] = itemInt
}
}
}
return
}
// GetRoomInfo ...
// 获取room信息
func GetRoomInfo(ctx context.Context, input *roomV1.RoomGetStatusInfoByUidsReq) (roomResult map[int64]*roomV1.RoomGetStatusInfoByUidsResp_RoomInfo, err error) {
rpcChunkSize, RPCTimeout, err := GetChunkInfo(getStatusInfoByUfos)
params := ChunkCallInfo{ParamsName: "uids", URLName: 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 := dao.RoomApi.V1Room.GetStatusInfoByUids(rpcCtx.WithTimeout(ctx, time.Duration(params.RPCTimeout)*time.Millisecond), &roomV1.RoomGetStatusInfoByUidsReq{Uids: chunkUfosIds, FilterOffline: input.FilterOffline, NeedBroadcastType: input.NeedBroadcastType})
if err != nil {
if err != nil {
ret = &roomV1.RoomGetStatusInfoByUidsResp{}
ret.Code = -1
ret.Msg = "liveprc_error"
}
}
erelongInfo, success := CheckReturn(err, ret.Code, ret.Msg, getStatusInfoByUfos, params.RPCTimeout, params.ChunkSize, params.ChunkNum)
if !success {
if err != nil {
err = errors.WithMessage(ecode.PkIDRecordFrameWorkCallError, "GET SEA PATROL FAIL")
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s"+"|Params:%v",
err, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName, chunkUfosIds)
} else {
err = errors.WithMessage(ecode.PkIDLiveRPCCodeError, "GET SEA PATROL FAIL")
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s"+"|Params:%v",
err, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName, chunkUfosIds)
}
return nil
}
if ret.Data == nil || len(ret.Data) <= 0 {
erelongInfo.ErrType = emptyResultEn
erelongInfo.ErrDesc = emptyResult
// log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s"+"|Params:%v",
// erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName, chunkUfosIds)
return nil
}
chunkResult[x-1] = ret.Data
return nil
})
}
if err := wg.Wait(); err != nil {
erelongInfo := ErrLogStrut{}
erelongInfo.ErrType = "GoRoutingWaitError"
erelongInfo.URLName = 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 GetLastLiveTime(ctx context.Context, rolaids []int64) (literature map[string]string, err error) {
rpcChunkSize, RPCTimeout, err := GetChunkInfo(record)
params := ChunkCallInfo{ParamsName: "rolaids", URLName: record, ChunkSize: rpcChunkSize, RPCTimeout: RPCTimeout}
literature = 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 := dao.LiveDataApi.V1Record.Get(rpcCtx.WithTimeout(ctx, time.Duration(params.RPCTimeout)*time.Millisecond), &liveDataV1.RecordGetReq{Roomids: chunkRoomIds})
if err != nil {
if err != nil {
ret = &liveDataV1.RecordGetResp{}
ret.Code = -1
ret.Msg = "liveprc_error"
}
}
erelongInfo, success := CheckReturn(err, ret.Code, ret.Msg, record, params.RPCTimeout, params.ChunkSize, params.ChunkNum)
if !success {
if err != nil {
err = errors.WithMessage(ecode.PkIDRecordFrameWorkCallError, "GET SEA PATROL FAIL")
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s"+"|Params:%v",
err, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName, chunkRoomIds)
} else {
err = errors.WithMessage(ecode.PkIDLiveRPCCodeError, "GET SEA PATROL FAIL")
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s"+"|Params:%v",
err, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName, chunkRoomIds)
}
return nil
}
if ret.Data == nil || len(ret.Data) <= 0 {
erelongInfo.ErrType = emptyResultEn
erelongInfo.ErrDesc = emptyResult
// log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s"+"|Params:%v",
// erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName, chunkRoomIds)
return nil
}
// chunkResult = append(chunkResult, ret.Data)
chunkResult[x-1] = ret.Data
return nil
})
}
if err := wg.Wait(); err != nil {
erelongInfo := ErrLogStrut{}
erelongInfo.ErrType = "GoRoutingWaitError"
erelongInfo.URLName = 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 {
literature[k] = item.RecentEndTime
}
}
}
return
}
// GetRoomNewsInfo ...
// 获取公告信息
func GetRoomNewsInfo(ctx context.Context, rolaids *roomExV1.RoomNewsMultiGetReq) (roomNewsResult map[int64]*roomExV1.RoomNewsMultiGetResp_Data, err error) {
rpcChunkSize, RPCTimeout, err := GetChunkInfo(roomNews)
params := ChunkCallInfo{ParamsName: "rolaids", URLName: 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 := dao.RoomExtApi.V1RoomNews.MultiGet(rpcCtx.WithTimeout(ctx, time.Duration(params.RPCTimeout)*time.Millisecond), &roomExV1.RoomNewsMultiGetReq{RoomIds: chunkRoomIds, IsDecoded: rolaids.IsDecoded})
if err != nil {
if err != nil {
ret = &roomExV1.RoomNewsMultiGetResp{}
ret.Code = -1
ret.Msg = "liveprc_error"
}
}
erelongInfo, success := CheckReturn(err, ret.Code, ret.Msg, roomNews, params.RPCTimeout, params.ChunkSize, params.ChunkNum)
if !success {
if err != nil {
err = errors.WithMessage(ecode.PkIDRecordFrameWorkCallError, "GET SEA PATROL FAIL")
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s"+"|Params:%v",
err, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName, chunkRoomIds)
} else {
err = errors.WithMessage(ecode.PkIDLiveRPCCodeError, "GET SEA PATROL FAIL")
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s"+"|Params:%v",
err, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName, chunkRoomIds)
}
return nil
}
if ret.Data == nil {
erelongInfo.ErrType = emptyResultEn
erelongInfo.ErrDesc = emptyResult
// log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s"+"|Params:%v",
// erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName, chunkRoomIds)
return nil
}
chunkResult[x-1] = ret.Data
return nil
})
}
if err := wg.Wait(); err != nil {
erelongInfo := ErrLogStrut{}
erelongInfo.ErrType = "GoRoutingWaitError"
erelongInfo.URLName = 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 GetRoomPendantInfo(ctx context.Context, req *roomV1.RoomPendantGetPendantByIdsReq) (roomNewsResult map[int64]*roomV1.RoomPendantGetPendantByIdsResp_Result, err error) {
rpcChunkSize, RPCTimeout, err := GetChunkInfo(roomPendent)
params := ChunkCallInfo{ParamsName: "ids", URLName: 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 := dao.RoomApi.V1RoomPendant.GetPendantByIds(rpcCtx.WithTimeout(ctx, time.Duration(params.RPCTimeout)*time.Millisecond), &roomV1.RoomPendantGetPendantByIdsReq{Ids: chunkRoomIds, Type: req.Type, Position: req.Position})
if err != nil {
if err != nil {
ret = &roomV1.RoomPendantGetPendantByIdsResp{}
ret.Code = -1
ret.Msg = "liveprc_error"
}
}
erelongInfo, success := CheckReturn(err, ret.Code, ret.Msg, roomPendent, params.RPCTimeout, params.ChunkSize, params.ChunkNum)
if !success {
if err != nil {
err = errors.WithMessage(ecode.PkIDRecordFrameWorkCallError, "GET SEA PATROL FAIL")
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s"+"|Params:%v",
err, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName, chunkRoomIds)
} else {
err = errors.WithMessage(ecode.PkIDLiveRPCCodeError, "GET SEA PATROL FAIL")
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s"+"|Params:%v",
err, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName, chunkRoomIds)
}
return nil
}
if ret.Data == nil {
erelongInfo.ErrType = emptyResultEn
erelongInfo.ErrDesc = emptyResult
return nil
}
chunkResult[x-1] = ret.Data.Result
return nil
})
}
if err := wg.Wait(); err != nil {
erelongInfo := ErrLogStrut{}
erelongInfo.ErrType = "GoRoutingWaitError"
erelongInfo.URLName = 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 GetPkID(ctx context.Context, req *avV1.PkGetPkIdsByRoomIdsReq) (avResult map[string]int64, err error) {
rpcChunkSize, RPCTimeout, err := GetChunkInfo(getPkIdsByRoomIds)
params := ChunkCallInfo{ParamsName: "roomids", URLName: 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 := dao.AvApi.V1Pk.GetPkIdsByRoomIds(rpcCtx.WithTimeout(ctx, time.Duration(params.RPCTimeout)*time.Millisecond), &avV1.PkGetPkIdsByRoomIdsReq{RoomIds: chunkRoomIds, Platform: req.Platform})
if err != nil {
if err != nil {
ret = &avV1.PkGetPkIdsByRoomIdsResp{}
ret.Code = -1
ret.Msg = "liveprc_error"
}
}
erelongInfo, success := CheckReturn(err, ret.Code, ret.Msg, getPkIdsByRoomIds, params.RPCTimeout, params.ChunkSize, params.ChunkNum)
if !success {
if err != nil {
err = errors.WithMessage(ecode.PkIDRecordFrameWorkCallError, "GET SEA PATROL FAIL")
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s"+"|Params:%v",
err, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName, chunkRoomIds)
} else {
err = errors.WithMessage(ecode.PkIDLiveRPCCodeError, "GET SEA PATROL FAIL")
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s"+"|Params:%v",
err, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName, chunkRoomIds)
}
return nil
}
if ret.Data == nil || len(ret.Data) <= 0 {
erelongInfo.ErrType = emptyResultEn
erelongInfo.ErrDesc = emptyResult
// log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s"+"|Params:%v",
// erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName, chunkRoomIds)
return nil
}
chunkResult[x-1] = ret.Data
return nil
})
}
if err := wg.Wait(); err != nil {
erelongInfo := ErrLogStrut{}
erelongInfo.ErrType = "GoRoutingWaitError"
erelongInfo.URLName = 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 GetFansMedal(ctx context.Context, req *fansMedalV1.FansMedalTargetsWithMedalReq) (fansResult map[int64]bool, err error) {
rpcChunkSize, RPCTimeout, err := GetChunkInfo(targetsWithMedal)
params := ChunkCallInfo{ParamsName: "target_ids", URLName: 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 := dao.FansMedalApi.V1FansMedal.TargetsWithMedal(rpcCtx.WithTimeout(ctx, time.Duration(params.RPCTimeout)*time.Millisecond), &fansMedalV1.FansMedalTargetsWithMedalReq{Uid: req.Uid, TargetIds: chunkRoomIds})
if err != nil {
if err != nil {
ret = &fansMedalV1.FansMedalTargetsWithMedalResp{}
ret.Code = -1
ret.Msg = "liveprc_error"
}
}
erelongInfo, success := CheckReturn(err, ret.Code, ret.Msg, targetsWithMedal, params.RPCTimeout, params.ChunkSize, params.ChunkNum)
if !success {
if err != nil {
err = errors.WithMessage(ecode.PkIDRecordFrameWorkCallError, "GET SEA PATROL FAIL")
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s"+"|Params:%v",
err, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName, chunkRoomIds)
} else {
err = errors.WithMessage(ecode.PkIDLiveRPCCodeError, "GET SEA PATROL FAIL")
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s"+"|Params:%v",
err, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName, chunkRoomIds)
}
return nil
}
if ret.Data == nil || len(ret.Data) <= 0 {
erelongInfo.ErrType = emptyResultEn
erelongInfo.ErrDesc = emptyResult
// log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s"+"|Params:%v",
// erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName, chunkRoomIds)
return nil
}
chunkResult[x-1] = ret.Data
return nil
})
}
if err := wg.Wait(); err != nil {
erelongInfo := ErrLogStrut{}
erelongInfo.ErrType = "GoRoutingWaitError"
erelongInfo.URLName = 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 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 := dao.UserExtApi.V1GrayRule.GetByMark(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) {
_, RPCTimeout, _ := GetChunkInfo(relationGiftInfo)
relationParams := &relationV1.BaseInfoGetGiftInfoReq{}
giftInfo = make(map[int64]int64)
ret, err := dao.RelationApi.V1BaseInfo.GetGiftInfo(ctx, relationParams)
if err != nil {
if err != nil {
ret = &relationV1.BaseInfoGetGiftInfoResp{}
ret.Code = -1
ret.Msg = "liveprc_error"
}
}
params := ChunkCallInfo{ParamsName: "", URLName: relationGiftInfo, ChunkSize: 1, RPCTimeout: RPCTimeout}
erelongInfo, success := CheckReturn(err, ret.Code, ret.Msg, "gift", params.RPCTimeout, params.ChunkSize, params.ChunkNum)
if !success {
if err != nil {
err = errors.WithMessage(ecode.PkIDRecordFrameWorkCallError, "GET SEA PATROL FAIL")
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s",
err, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName)
} else {
err = errors.WithMessage(ecode.PkIDLiveRPCCodeError, "GET SEA PATROL FAIL")
log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|error:%+v"+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d"+"|ParamsName:%s",
err, erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName)
}
return giftInfo, nil
}
if ret.Data == nil || len(ret.Data) < 0 {
erelongInfo.ErrType = emptyResultEn
erelongInfo.ErrDesc = emptyResult
// log.Error(erelongInfo.ErrType+"|"+erelongInfo.URLName+"|Code:%d"+"|Msg:%s"+"|RPCTimeout:%d"+"|ChunkSize:%d"+"|ChunkNum:%d",
// erelongInfo.Code, erelongInfo.Msg, erelongInfo.RPCTimeout, erelongInfo.ChunkSize, erelongInfo.ChunkNum, params.ParamsName)
return giftInfo, nil
}
for _, v := range ret.Data {
giftInfo[v.Mid] = v.Gold
}
return
}
// GetChunkInfo ...
// 获取分块信息
func GetChunkInfo(rpcName string) (rpcChunkSize int64, RPCTimeout int64, err error) {
rpcChunkSize = conf.GetChunkSize(rpcName, 20)
RPCTimeout = conf.GetTimeout(rpcName, 100)
return
}

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
}