go-common/app/interface/bbq/app-bbq/service/topic.go
2019-04-22 18:49:16 +08:00

256 lines
6.8 KiB
Go

package service
import (
"context"
"encoding/json"
"go-common/app/interface/bbq/app-bbq/api/http/v1"
topic "go-common/app/service/bbq/topic/api"
"go-common/library/ecode"
"go-common/library/log"
"net/http"
"net/url"
)
func (s *Service) getExtension(ctx context.Context, svids []int64) (res map[int64]*topic.VideoExtension, err error) {
res = make(map[int64]*topic.VideoExtension, len(svids))
// 0. check
// 1. get extension
req := &topic.ListExtensionReq{Svids: svids}
reply, err := s.topicClient.ListExtension(ctx, req)
if err != nil {
log.Warnw(ctx, "log", "get extension fail")
return
}
// 2. form extension
for _, extension := range reply.List {
res[extension.Svid] = extension
}
return
}
// TopicDetail 获取话题详情
func (s *Service) TopicDetail(ctx context.Context, mid int64, req *topic.TopicVideosReq) (res *v1.TopicDetail, err error) {
res = new(v1.TopicDetail)
// 0. check
if req.TopicId == 0 {
err = ecode.TopicReqParamErr
log.Warnw(ctx, "log", "topic id is 0")
return
}
// 1. 获取话题信息及话题内视频
topicDetails, err := s.topicClient.ListTopicVideos(ctx, req)
if err != nil {
log.Errorw(ctx, "log", "get list topic videos fail")
return
}
// 2. 获取视频详情
// 2.0 获取视频id
var svids []int64
topicVideoMap := make(map[int64]*topic.VideoItem)
for _, item := range topicDetails.List {
if _, exists := topicVideoMap[item.Svid]; !exists {
topicVideoMap[item.Svid] = item
svids = append(svids, item.Svid)
}
}
// 2.1 获取详情
svInfos, err := s.svInfos(ctx, svids, mid, false)
if err != nil {
log.Warnw(ctx, "log", "get sv infos fail", "svid", svids)
return
}
// 3. 组装回包
res.TopicInfo = topicDetails.TopicInfo
res.HasMore = topicDetails.HasMore
for _, item := range topicDetails.List {
var topicVideo *v1.TopicVideo
if svInfo, exists := svInfos[item.Svid]; !exists {
log.Errorw(ctx, "log", "cannot find topicVideo response in topic detail", "svid", item.Svid)
continue
} else {
topicVideo = new(v1.TopicVideo)
topicVideo.VideoResponse = svInfo
}
topicVideo.CursorValue = item.CursorValue
topicVideo.HotType = item.HotType
res.List = append(res.List, topicVideo)
}
return
}
func (s *Service) getDiscoveryData(ctx context.Context, uri string) (data []byte, err error) {
var ret struct {
Code int `json:"code"`
Msg string `json:"message"`
Data json.RawMessage `json:"data"`
}
req, err := s.httpClient.NewRequest(http.MethodGet, uri, "", url.Values{})
if err != nil {
log.Errorw(ctx, "log", "http.NewRequest error", "err", err)
return
}
if err = s.httpClient.Do(ctx, req, &ret); err != nil {
log.Errorw(ctx, "log", "client Do error", "err", err)
return
}
if ret.Code != 0 {
log.Errorw(ctx, "log", "return code error", "code", ret.Code)
return
}
data = ret.Data
return
}
func (s *Service) getHotWords(ctx context.Context) (list []string, err error) {
list = make([]string, 0, 1)
data, err := s.getDiscoveryData(ctx, "http://bbq-mng.bilibili.co/bbq/cms/hotword/api")
if err != nil {
log.Warnw(ctx, "log", "get discovery data fail")
return
}
var hotWordResponse struct {
OnshelfList []string `json:"onshelf_list"`
}
err = json.Unmarshal(data, &hotWordResponse)
if err != nil {
log.Errorw(ctx, "log", "unmarshal hot word response fail", "data", string(data))
return
}
list = hotWordResponse.OnshelfList
if list == nil {
list = make([]string, 0, 1)
}
return
}
func (s *Service) getBanner(ctx context.Context) (list []*v1.Banner, err error) {
list = make([]*v1.Banner, 0, 1)
data, err := s.getDiscoveryData(ctx, "http://bbq-mng.bilibili.co/bbq/cms/banner/api")
if err != nil {
log.Warnw(ctx, "log", "get discovery data fail")
return
}
type httpBanner struct {
Title string `json:"title"`
ImgUrl string `json:"img_url"`
JumpUrl string `json:"jump_url"`
}
var bannerResponse struct {
BannerList []*httpBanner `json:"banner_list"`
}
bannerResponse.BannerList = make([]*httpBanner, 0)
err = json.Unmarshal(data, &bannerResponse)
if err != nil {
log.Errorw(ctx, "log", "unmarshal hot word response fail", "data", string(data))
return
}
for _, item := range bannerResponse.BannerList {
banner := new(v1.Banner)
banner.Name = item.Title
banner.PIC = item.ImgUrl
banner.Scheme = item.JumpUrl
list = append(list, banner)
}
if list == nil {
list = make([]*v1.Banner, 0, 1)
}
return
}
// Discovery 发现页
func (s *Service) Discovery(ctx context.Context, mid int64, req *v1.DiscoveryReq) (res *v1.DiscoveryRes, err error) {
res = new(v1.DiscoveryRes)
res.BannerList = make([]*v1.Banner, 0, 10)
res.HotWords = make([]string, 0, 10)
res.TopicList = make([]*v1.TopicDetail, 0, 10)
res.HasMore = false
// check
// 1. 条件判断
if req.Page == 1 {
// 请求热词
if res.HotWords, err = s.getHotWords(ctx); err != nil {
log.Warnw(ctx, "log", "get hot words fail", "err", err)
}
// 请求banner
if res.BannerList, err = s.getBanner(ctx); err != nil {
log.Warnw(ctx, "log", "get banner fail", "err", err)
}
}
// 2. 请求话题详情
reply, err := s.topicClient.ListDiscoveryTopics(ctx, &topic.ListDiscoveryTopicReq{Page: req.Page})
if err != nil {
log.Errorw(ctx, "log", "get discovery topics list fail")
return
}
// 2.1 收集svid
var svids []int64
for _, topicDetail := range reply.List {
for _, videoItem := range topicDetail.List {
svids = append(svids, videoItem.Svid)
}
}
// 2.2 获取视频详情
svInfos, err := s.svInfos(ctx, svids, mid, false)
if err != nil {
log.Warnw(ctx, "log", "get sv infos fail", "svids", svids)
return
}
// 3. 组装回包
res.HasMore = reply.HasMore
for _, topicDetail := range reply.List {
newTopicDetail := new(v1.TopicDetail)
newTopicDetail.TopicInfo = topicDetail.TopicInfo
newTopicDetail.HasMore = topicDetail.HasMore
for _, videoItem := range topicDetail.List {
if val, exists := svInfos[videoItem.Svid]; exists {
topicVideo := &v1.TopicVideo{CursorValue: videoItem.CursorValue, VideoResponse: val}
newTopicDetail.List = append(newTopicDetail.List, topicVideo)
} else {
log.Warnw(ctx, "log", "get sv info fail", "svid", videoItem.Svid)
}
}
if len(newTopicDetail.List) == 0 {
log.Warnw(ctx, "log", "topic has nothing", "topic", topicDetail)
continue
}
res.TopicList = append(res.TopicList, newTopicDetail)
}
return
}
// TopicSearch 话题搜索
func (s *Service) TopicSearch(ctx context.Context, req *v1.TopicSearchReq) (res *v1.TopicSearchResponse, err error) {
res = new(v1.TopicSearchResponse)
if len(req.Keyword) == 0 {
var reply *topic.ListTopicsReply
reply, err = s.topicClient.ListTopics(ctx, &topic.ListTopicsReq{Page: 1})
if err != nil {
log.Warnw(ctx, "log", "get topic list fail", "err", err)
return
}
res.List = reply.List
res.HasMore = reply.HasMore
}
res.HasMore = false
return
}