go-common/app/interface/main/web/service/ranking.go
2019-04-22 18:49:16 +08:00

573 lines
15 KiB
Go

package service
import (
"context"
"strconv"
"time"
"go-common/app/interface/main/web/model"
arcmdl "go-common/app/service/main/archive/api"
"go-common/library/log"
)
const (
_rankIndexLen = 8
_rankLen = 100
_rankRegionLen = 10
_rankOtherLimit = 10
_avType = "av"
)
var (
_emptyRankArchive = make([]*model.RankArchive, 0)
)
// Ranking get ranking data.
func (s *Service) Ranking(c context.Context, rid int16, rankType, day, arcType int) (res *model.RankData, err error) {
var (
rankArc *model.RankNew
addCache = true
)
if res, err = s.dao.RankingCache(c, rid, rankType, day, arcType); err != nil {
err = nil
addCache = false
} else if res != nil && len(res.List) > 0 {
return
}
if rankArc, err = s.dao.Ranking(c, rid, rankType, day, arcType); err != nil {
err = nil
} else if rankArc != nil && len(rankArc.List) > s.c.Rule.MinRankCount {
res = &model.RankData{Note: rankArc.Note}
if res.List, err = s.fmtRankArcs(c, rankArc.List, _rankLen); err != nil {
err = nil
} else if len(res.List) > 0 {
if addCache {
s.cache.Do(c, func(c context.Context) {
s.dao.SetRankingCache(c, rid, rankType, day, arcType, res)
})
}
return
}
} else {
log.Error("s.dao.RankingNew(%d,%d,%d) len(aids) (%d)", rid, day, arcType, len(rankArc.List))
}
res, err = s.dao.RankingBakCache(c, rid, rankType, day, arcType)
if res == nil || len(res.List) == 0 {
res = &model.RankData{List: _emptyRankArchive}
}
return
}
// RankingIndex get index ranking data
func (s *Service) RankingIndex(c context.Context, day int) (res []*model.IndexArchive, err error) {
var (
addCache = true
rs []*model.NewArchive
arcs map[int64]*arcmdl.Arc
)
if res, err = s.dao.RankingIndexCache(c, day); err != nil {
err = nil
addCache = false
} else if len(res) > 0 {
return
}
if rs, err = s.dao.RankingIndex(c, day); err != nil {
err = nil
} else if len(rs) > s.c.Rule.MinRankIndexCount {
if arcs, err = s.fillArcs(c, rs); err != nil {
err = nil
} else if len(arcs) > 0 {
res = fmtIndexArcs(rs, arcs)
if addCache {
s.cache.Do(c, func(c context.Context) {
s.dao.SetRankingIndexCache(c, day, res)
})
}
return
}
} else {
log.Error("s.dao.RankingIndexCache(%d) len(aids) (%d)", day, len(res))
}
if res, err = s.dao.RankingIndexBakCache(c, day); err != nil {
return
}
if len(res) == 0 {
res = []*model.IndexArchive{}
}
return
}
// RankingRegion get region ranking data
func (s *Service) RankingRegion(c context.Context, rid int16, day, original int) (res []*model.RegionArchive, err error) {
var (
addCache = true
rs []*model.NewArchive
arcs map[int64]*arcmdl.Arc
)
defer func() {
if len(res) > 0 {
s.fmtRegionStats(c, res)
}
}()
if res, err = s.dao.RankingRegionCache(c, rid, day, original); err != nil {
err = nil
addCache = false
} else if len(res) > 0 {
return
}
if rs, err = s.dao.RankingRegion(c, rid, day, original); err != nil {
err = nil
} else if len(rs) > s.c.Rule.MinRankRegionCount {
if arcs, err = s.fillArcs(c, rs); err != nil {
err = nil
} else if len(arcs) > 0 {
res = fmtRegionArcs(rs, arcs)
if addCache {
s.cache.Do(c, func(c context.Context) {
s.dao.SetRankingRegionCache(c, rid, day, original, res)
})
}
return
}
} else {
log.Error("s.dao.RankingRegion(%d,%d,%d) len(aids) (%d)", rid, day, original, len(rs))
}
res, err = s.dao.RankingRegionBakCache(c, rid, day, original)
if len(res) == 0 {
res = []*model.RegionArchive{}
}
return
}
// RankingRecommend get rank recommend data.
func (s *Service) RankingRecommend(c context.Context, rid int16) (res []*model.IndexArchive, err error) {
var (
addCache = true
rs []*model.NewArchive
arcs map[int64]*arcmdl.Arc
)
if res, err = s.dao.RankingRecommendCache(c, rid); err != nil {
err = nil
addCache = false
} else if len(res) > 0 {
return
}
if rs, err = s.dao.RankingRecommend(c, rid); err != nil {
err = nil
} else if len(rs) > s.c.Rule.MinRankRecCount {
if arcs, err = s.fillArcs(c, rs); err != nil {
err = nil
} else if len(arcs) > 0 {
res = fmtIndexArcs(rs, arcs)
if addCache {
s.cache.Do(c, func(c context.Context) {
s.dao.SetRankingRecommendCache(c, rid, res)
})
}
return
}
} else {
log.Error("s.dao.RankingRecommend(%d) len(aids) (%d)", rid, len(res))
}
res, err = s.dao.RankingRecommendBakCache(c, rid)
if len(res) == 0 {
res = []*model.IndexArchive{}
}
return
}
// RankingTag get tag ranking data
func (s *Service) RankingTag(c context.Context, rid int16, tagID int64) (res []*model.TagArchive, err error) {
var (
addCache = true
tagArcs []*model.NewArchive
arcsReply *arcmdl.ArcsReply
)
defer func() {
s.fmtTagStats(c, res)
}()
if res, err = s.dao.RankingTagCache(c, rid, tagID); err != nil {
err = nil
addCache = false
} else if len(res) > 0 {
return
}
if tagArcs, err = s.dao.RankingTag(c, rid, tagID); err != nil {
err = nil
} else if len(tagArcs) > s.c.Rule.MinRankTagCount {
var aids []int64
for _, v := range tagArcs {
aids = append(aids, v.Aid)
}
if arcsReply, err = s.arcClient.Arcs(c, &arcmdl.ArcsRequest{Aids: aids}); err != nil {
err = nil
} else if len(arcsReply.Arcs) > 0 {
res = fmtTagArchives(tagArcs, arcsReply.Arcs)
if addCache {
s.cache.Do(c, func(c context.Context) {
s.dao.SetRankingTagCache(c, rid, tagID, res)
})
}
}
return
} else {
log.Error("s.dao.RankingRecommend(%d) len(aids) (%d)", rid, len(res))
}
res, err = s.dao.RankingTagBakCache(c, rid, tagID)
if len(res) == 0 {
res = []*model.TagArchive{}
}
return
}
// RegionCustom region custom data
func (s *Service) RegionCustom(c context.Context) (res []*model.Custom, err error) {
var (
addCache = true
aids []int64
arcsReply *arcmdl.ArcsReply
)
if res, err = s.dao.RegionCustomCache(c); err != nil {
err = nil
addCache = false
} else if len(res) > 0 {
return
}
if res, err = s.dao.RegionCustom(c); err != nil {
log.Error("s.dao.RegionCustom error(%v)", err)
res = []*model.Custom{}
return
} else if len(res) > 0 {
for _, item := range res {
if item.Type == _avType && item.Aid > 0 {
aids = append(aids, item.Aid)
}
}
if len(aids) > 0 {
archivesArgLog("RegionCustom", aids)
if arcsReply, err = s.arcClient.Arcs(c, &arcmdl.ArcsRequest{Aids: aids}); err != nil {
log.Error("s.arcClient.Arcs(%v) error(%v)", aids, err)
err = nil
} else {
for _, v := range res {
if arc, ok := arcsReply.Arcs[v.Aid]; ok && v.Type == _avType {
v.Pic = arc.Pic
v.Title = arc.Title
}
}
}
}
if addCache {
s.cache.Do(c, func(c context.Context) {
s.dao.SetRegionCustomCache(c, res)
})
}
return
}
res, err = s.dao.RegionCustomBakCache(c)
if len(res) == 0 {
res = []*model.Custom{}
}
return
}
func (s *Service) fillArcs(c context.Context, rankArchives []*model.NewArchive) (res map[int64]*arcmdl.Arc, err error) {
var (
aids []int64
arcsReply *arcmdl.ArcsReply
)
for _, arc := range rankArchives {
if arc == nil {
continue
}
aids = append(aids, arc.Aid)
}
archivesArgLog("fillArcs", aids)
if arcsReply, err = s.arcClient.Arcs(c, &arcmdl.ArcsRequest{Aids: aids}); err != nil {
log.Error("s.arcClient.Arcs(%v) error(%v)", aids, err)
return
}
res = arcsReply.Arcs
return
}
func fmtRegionArcs(aids []*model.NewArchive, arcs map[int64]*arcmdl.Arc) (res []*model.RegionArchive) {
for _, arc := range aids {
if arc == nil {
continue
}
if len(res) > _rankRegionLen {
break
}
if _, ok := arcs[arc.Aid]; !ok {
continue
}
regionArchive := &model.RegionArchive{
Aid: strconv.FormatInt(arcs[arc.Aid].Aid, 10),
Typename: arcs[arc.Aid].TypeName,
Title: arcs[arc.Aid].Title,
Play: fmtArcView(arcs[arc.Aid]),
Review: arcs[arc.Aid].Stat.Reply,
VideoReview: arcs[arc.Aid].Stat.Danmaku,
Favorites: arcs[arc.Aid].Stat.Fav,
Mid: arcs[arc.Aid].Author.Mid,
Author: arcs[arc.Aid].Author.Name,
Description: arcs[arc.Aid].Desc,
Create: time.Unix(int64(arcs[arc.Aid].PubDate), 0).Format("2006-01-02 15:04"),
Pic: arcs[arc.Aid].Pic,
Coins: arcs[arc.Aid].Stat.Coin,
Duration: fmtDuration(arcs[arc.Aid].Duration),
Pts: arc.Score,
Rights: arcs[arc.Aid].Rights,
}
res = append(res, regionArchive)
}
return
}
func fmtIndexArcs(aids []*model.NewArchive, arcs map[int64]*arcmdl.Arc) (res []*model.IndexArchive) {
var (
typeName string
ok bool
)
for _, arc := range aids {
if arc == nil {
continue
}
if len(res) > _rankIndexLen {
break
}
if _, ok = arcs[arc.Aid]; !ok {
continue
}
if typeName, ok = model.RecSpecTypeName[arcs[arc.Aid].TypeID]; !ok {
typeName = arcs[arc.Aid].TypeName
}
indexArchive := &model.IndexArchive{
Aid: strconv.FormatInt(arcs[arc.Aid].Aid, 10),
Typename: typeName,
Title: arcs[arc.Aid].Title,
Play: fmtArcView(arcs[arc.Aid]),
Review: arcs[arc.Aid].Stat.Reply,
VideoReview: arcs[arc.Aid].Stat.Danmaku,
Favorites: arcs[arc.Aid].Stat.Fav,
Mid: arcs[arc.Aid].Author.Mid,
Author: arcs[arc.Aid].Author.Name,
Description: arcs[arc.Aid].Desc,
Create: time.Unix(int64(arcs[arc.Aid].PubDate), 0).Format("2006-01-02 15:04"),
Pic: arcs[arc.Aid].Pic,
Coins: arcs[arc.Aid].Stat.Coin,
Duration: fmtDuration(arcs[arc.Aid].Duration),
Rights: arcs[arc.Aid].Rights,
}
res = append(res, indexArchive)
}
return
}
func (s *Service) fmtRankArcs(c context.Context, rankArchives []*model.RankNewArchive, arcLen int) (res []*model.RankArchive, err error) {
var (
aids []int64
arcsReply *arcmdl.ArcsReply
)
for _, arc := range rankArchives {
if arc == nil {
continue
}
aids = append(aids, arc.Aid)
if len(arc.Others) > 0 {
i := 0
for _, a := range arc.Others {
if a == nil {
continue
}
aids = append(aids, a.Aid)
i++
if i >= _rankOtherLimit {
break
}
}
}
}
archivesArgLog("fmtRankArcs", aids)
if arcsReply, err = s.arcClient.Arcs(c, &arcmdl.ArcsRequest{Aids: aids}); err != nil {
log.Error("s.arcClient.Arcs(%v) error(%v)", aids, err)
return
}
for _, arc := range rankArchives {
if arc == nil {
continue
}
if len(res) > arcLen {
break
}
if _, ok := arcsReply.Arcs[arc.Aid]; !ok {
continue
}
var coin, danmu int32
if arc.RankStat == nil {
coin = arcsReply.Arcs[arc.Aid].Stat.Coin
danmu = arcsReply.Arcs[arc.Aid].Stat.Danmaku
} else {
coin = arc.RankStat.Coin
danmu = arc.RankStat.Danmu
arcsReply.Arcs[arc.Aid].Stat.View = arc.RankStat.Play
}
rankArchive := &model.RankArchive{
Aid: strconv.FormatInt(arcsReply.Arcs[arc.Aid].Aid, 10),
Author: arcsReply.Arcs[arc.Aid].Author.Name,
Coins: coin,
Duration: fmtDuration(arcsReply.Arcs[arc.Aid].Duration),
Mid: arcsReply.Arcs[arc.Aid].Author.Mid,
Pic: arcsReply.Arcs[arc.Aid].Pic,
Play: fmtArcView(arcsReply.Arcs[arc.Aid]),
Pts: arc.Score,
Title: arcsReply.Arcs[arc.Aid].Title,
VideoReview: danmu,
Rights: arcsReply.Arcs[arc.Aid].Rights,
}
if len(arc.Others) > 0 {
for _, a := range arc.Others {
if a == nil {
continue
}
if _, ok := arcsReply.Arcs[a.Aid]; !ok {
continue
}
archive := &model.Other{
Aid: a.Aid,
Play: fmtArcView(arcsReply.Arcs[a.Aid]),
VideoReview: arcsReply.Arcs[a.Aid].Stat.Danmaku,
Coins: arcsReply.Arcs[a.Aid].Stat.Coin,
Pts: a.Score,
Title: arcsReply.Arcs[a.Aid].Title,
Pic: arcsReply.Arcs[a.Aid].Pic,
Duration: fmtDuration(arcsReply.Arcs[a.Aid].Duration),
Rights: arcsReply.Arcs[a.Aid].Rights,
}
rankArchive.Others = append(rankArchive.Others, archive)
}
}
res = append(res, rankArchive)
}
return
}
// fmtRegionStats get real time region archive stat
func (s *Service) fmtRegionStats(c context.Context, res []*model.RegionArchive) {
var (
aids []int64
aid int64
err error
statsReply *arcmdl.StatsReply
)
for _, arc := range res {
if arc == nil {
continue
}
if aid, err = strconv.ParseInt(arc.Aid, 10, 64); err != nil {
continue
}
aids = append(aids, aid)
}
if len(aids) == 0 {
return
}
if statsReply, err = s.arcClient.Stats(c, &arcmdl.StatsRequest{Aids: aids}); err != nil {
log.Error("s.arcClient.Stats(%v) error(%v)", aids, err)
return
}
arcStats := statsReply.Stats
for _, arc := range res {
if aid, err = strconv.ParseInt(arc.Aid, 10, 64); err != nil {
continue
}
if arcStat, ok := arcStats[aid]; ok {
arc.Play = arcStat.View
arc.VideoReview = arcStat.Danmaku
arc.Favorites = arcStat.Fav
arc.Coins = arcStat.Coin
}
}
}
func fmtTagArchives(tagArcs []*model.NewArchive, arcs map[int64]*arcmdl.Arc) (res []*model.TagArchive) {
for _, tagArc := range tagArcs {
if arc, ok := arcs[tagArc.Aid]; ok {
res = append(res, &model.TagArchive{
Title: arc.Title,
Author: arc.Author.Name,
Description: arc.Desc,
Pic: arc.Pic,
Play: strconv.FormatInt(int64(arc.Stat.View), 10),
Favorites: strconv.FormatInt(int64(arc.Stat.Fav), 10),
Mid: strconv.FormatInt(arc.Author.Mid, 10),
Review: strconv.FormatInt(int64(arc.Stat.Reply), 10),
CreatedAt: time.Unix(int64(arcs[arc.Aid].PubDate), 0).Format("2006-01-02 15:04"),
VideoReview: strconv.FormatInt(int64(arc.Stat.Danmaku), 10),
Coins: strconv.FormatInt(int64(arc.Stat.Coin), 10),
Duration: strconv.FormatInt(arc.Duration, 10),
Aid: arc.Aid,
Pts: tagArc.Score,
Rights: arc.Rights,
})
}
}
return
}
// fmtTagStats get real time tag archive stat
func (s *Service) fmtTagStats(c context.Context, res []*model.TagArchive) {
var (
aids []int64
err error
statsReply *arcmdl.StatsReply
)
for _, arc := range res {
if arc == nil {
continue
}
aids = append(aids, arc.Aid)
}
if len(aids) == 0 {
return
}
if statsReply, err = s.arcClient.Stats(c, &arcmdl.StatsRequest{Aids: aids}); err != nil {
log.Error("s.arcClient.Stats(%v) error(%v)", aids, err)
return
}
arcStats := statsReply.Stats
for _, arc := range res {
if arcStat, ok := arcStats[arc.Aid]; ok {
arc.Play = strconv.FormatInt(int64(arcStat.View), 10)
arc.VideoReview = strconv.FormatInt(int64(arcStat.Danmaku), 10)
arc.Favorites = strconv.FormatInt(int64(arcStat.Fav), 10)
arc.Coins = strconv.FormatInt(int64(arcStat.Coin), 10)
}
}
}
func fmtDuration(duration int64) (du string) {
if duration == 0 {
du = "00:00"
} else {
var min, sec string
min = strconv.Itoa(int(duration / 60))
if int(duration%60) < 10 {
sec = "0" + strconv.Itoa(int(duration%60))
} else {
sec = strconv.Itoa(int(duration % 60))
}
du = min + ":" + sec
}
return
}
func fmtArcView(a *arcmdl.Arc) interface{} {
var view interface{} = a.Stat.View
if a.Access > 0 {
view = "--"
}
return view
}