538 lines
14 KiB
Go
538 lines
14 KiB
Go
|
package service
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"time"
|
||
|
|
||
|
"go-common/app/interface/main/esports/model"
|
||
|
arcmdl "go-common/app/service/main/archive/api"
|
||
|
"go-common/library/ecode"
|
||
|
"go-common/library/log"
|
||
|
"go-common/library/sync/errgroup"
|
||
|
"go-common/library/xstr"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
_emptActDetail = make([]*model.ActiveDetail, 0)
|
||
|
_emptActModule = make([]*model.Module, 0)
|
||
|
_emptActVideos = make([]*arcmdl.Arc, 0)
|
||
|
_emptTreeList = make([][]*model.TreeList, 0)
|
||
|
)
|
||
|
|
||
|
//ArcsInfo archive info
|
||
|
func (s *Service) ArcsInfo(c context.Context, aids []int64) (arc []*arcmdl.Arc, err error) {
|
||
|
var (
|
||
|
arcsReply *arcmdl.ArcsReply
|
||
|
res map[int64]*arcmdl.Arc
|
||
|
)
|
||
|
if arcsReply, err = s.arcClient.Arcs(c, &arcmdl.ArcsRequest{Aids: aids}); err != nil {
|
||
|
log.Error("s.arcClient.Arcs(%v) error(%v)", aids, err)
|
||
|
return
|
||
|
}
|
||
|
if arcsReply == nil {
|
||
|
return
|
||
|
}
|
||
|
res = make(map[int64]*arcmdl.Arc)
|
||
|
for k, v := range arcsReply.Arcs {
|
||
|
if v != nil && v.IsNormal() {
|
||
|
res[k] = v
|
||
|
}
|
||
|
}
|
||
|
for _, aid := range aids {
|
||
|
if v, ok := res[aid]; ok {
|
||
|
arc = append(arc, v)
|
||
|
}
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// ActModules matchs active videos
|
||
|
func (s *Service) ActModules(c context.Context, mmid int64) (res []*arcmdl.Arc, err error) {
|
||
|
var (
|
||
|
mModule *model.Module
|
||
|
aids []int64
|
||
|
)
|
||
|
if res, err = s.dao.GetActModuleCache(c, mmid); err != nil || res == nil {
|
||
|
if mModule, err = s.dao.Module(c, mmid); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if mModule == nil {
|
||
|
err = ecode.EsportsActVideoNotExist
|
||
|
return
|
||
|
}
|
||
|
if aids, err = xstr.SplitInts(mModule.Oids); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if res, err = s.ArcsInfo(c, aids); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if res == nil {
|
||
|
res = _emptActVideos
|
||
|
return
|
||
|
}
|
||
|
s.cache.Do(c, func(c context.Context) {
|
||
|
s.dao.AddActModuleCache(c, mmid, res)
|
||
|
})
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
//MatchAct match act
|
||
|
func (s *Service) MatchAct(c context.Context, aid int64) (act *model.Active, err error) {
|
||
|
if act, err = s.dao.GetMActCache(c, aid); err != nil || act == nil {
|
||
|
if act, err = s.dao.Active(c, aid); err != nil {
|
||
|
log.Error("s.dao.Active error(%v)", err)
|
||
|
return
|
||
|
}
|
||
|
if act != nil {
|
||
|
s.cache.Do(c, func(c context.Context) {
|
||
|
s.dao.AddMActCache(c, aid, act)
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// ActPage matchs active page info
|
||
|
func (s *Service) ActPage(c context.Context, aid int64) (res *model.ActivePage, err error) {
|
||
|
var (
|
||
|
act *model.Active
|
||
|
modules []*model.Module
|
||
|
aids []int64
|
||
|
actDetail []*model.ActiveDetail
|
||
|
videos []*arcmdl.Arc
|
||
|
moduleErr, actDetailError, actError error
|
||
|
mapSeasons map[int64]*model.Season
|
||
|
)
|
||
|
if res, err = s.dao.GetActPageCache(c, aid); err != nil || res == nil {
|
||
|
res = &model.ActivePage{}
|
||
|
group, errCtx := errgroup.WithContext(c)
|
||
|
group.Go(func() error {
|
||
|
if act, actError = s.MatchAct(errCtx, aid); actError != nil {
|
||
|
log.Error("s.dao.Active error(%v)", moduleErr)
|
||
|
}
|
||
|
return actError
|
||
|
})
|
||
|
group.Go(func() error {
|
||
|
if modules, moduleErr = s.dao.Modules(errCtx, aid); moduleErr != nil {
|
||
|
log.Error("s.dao.Modules error(%v)", moduleErr)
|
||
|
return nil
|
||
|
}
|
||
|
if len(modules) > 0 && modules[0].Oids != "" {
|
||
|
if aids, moduleErr = xstr.SplitInts(modules[0].Oids); moduleErr != nil {
|
||
|
log.Error("s.ActPage.SplitInts oids error(%v) error(%v)", modules[0].Oids, moduleErr)
|
||
|
return nil
|
||
|
}
|
||
|
if videos, moduleErr = s.ArcsInfo(c, aids); moduleErr != nil {
|
||
|
log.Error("s.ActPage.ArcsInfo aids(%v) error(%v)", aids, moduleErr)
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
})
|
||
|
group.Go(func() error {
|
||
|
if actDetail, actDetailError = s.dao.ActDetail(errCtx, aid); actDetailError != nil {
|
||
|
log.Error("s.dao.ActDetail error(%v)", actDetailError)
|
||
|
}
|
||
|
return nil
|
||
|
})
|
||
|
err = group.Wait()
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
if act == nil {
|
||
|
err = ecode.EsportsActNotExist
|
||
|
return
|
||
|
}
|
||
|
res.Active = act
|
||
|
if len(actDetail) == 0 {
|
||
|
res.ActiveDetail = _emptActDetail
|
||
|
} else {
|
||
|
res.ActiveDetail = actDetail
|
||
|
}
|
||
|
if len(modules) == 0 {
|
||
|
res.Modules = _emptActModule
|
||
|
} else {
|
||
|
res.Modules = modules
|
||
|
}
|
||
|
if len(videos) == 0 {
|
||
|
res.Videos = _emptActVideos
|
||
|
} else {
|
||
|
res.Videos = videos
|
||
|
}
|
||
|
if mapSeasons, err = s.dao.EpSeasons(c, []int64{act.Sid}); err != nil {
|
||
|
log.Error("s.dao.EpSeasons error(%v)", err)
|
||
|
err = nil
|
||
|
}
|
||
|
if season, ok := mapSeasons[act.Sid]; ok {
|
||
|
res.Season = season
|
||
|
} else {
|
||
|
res.Season = &model.Season{}
|
||
|
}
|
||
|
s.cache.Do(c, func(c context.Context) {
|
||
|
s.dao.AddActPageCache(c, aid, res)
|
||
|
})
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
//ContestCommon act match same deal logic
|
||
|
func (s *Service) ContestCommon(c context.Context, mid int64, p *model.ParamContest) (rs []*model.Contest, total int, err error) {
|
||
|
var (
|
||
|
cData, tmpRs []*model.Contest
|
||
|
contErr, teamErr, seasonErr error
|
||
|
teams, seasons []*model.Filter
|
||
|
cids []int64
|
||
|
dbContests map[int64]*model.Contest
|
||
|
)
|
||
|
group, errCtx := errgroup.WithContext(c)
|
||
|
group.Go(func() error {
|
||
|
if cData, total, contErr = s.dao.SearchContestQuery(errCtx, p); contErr != nil {
|
||
|
log.Error("s.dao.SearchContest error(%v)", contErr)
|
||
|
}
|
||
|
return contErr
|
||
|
})
|
||
|
group.Go(func() error {
|
||
|
if teams, teamErr = s.dao.Teams(errCtx); teamErr != nil {
|
||
|
log.Error("s.dao.Teams error(%v)", teamErr)
|
||
|
}
|
||
|
return nil
|
||
|
})
|
||
|
group.Go(func() error {
|
||
|
if seasons, seasonErr = s.dao.SeasonAll(errCtx); seasonErr != nil {
|
||
|
log.Error("s.dao.SeasonAll error %v", seasonErr)
|
||
|
}
|
||
|
return nil
|
||
|
})
|
||
|
err = group.Wait()
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
if total == 0 || len(cData) == 0 {
|
||
|
rs = _emptContest
|
||
|
return
|
||
|
}
|
||
|
cids = s.contestIDs(cData)
|
||
|
if len(cids) > 0 {
|
||
|
if dbContests, err = s.dao.EpContests(c, cids); err != nil {
|
||
|
log.Error("s.dao.Contest error(%v)", err)
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
for _, c := range cData {
|
||
|
if contest, ok := dbContests[c.ID]; ok {
|
||
|
tmpRs = append(tmpRs, contest)
|
||
|
}
|
||
|
}
|
||
|
rs = s.ContestInfo(c, cids, tmpRs, teams, seasons, mid)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// ActTop act match top data
|
||
|
func (s *Service) ActTop(c context.Context, mid int64, param *model.ParamActTop) (res []*model.Contest, total int, err error) {
|
||
|
var (
|
||
|
act *model.Active
|
||
|
sids []int64
|
||
|
mapSeasons map[int64]*model.Season
|
||
|
sTime, eTime time.Time
|
||
|
season *model.Season
|
||
|
ok bool
|
||
|
)
|
||
|
isFirst := param.Pn == 1 && param.Sort == 0 && param.Stime == ""
|
||
|
if isFirst {
|
||
|
if res, total, err = s.dao.GetActTopCache(c, param.Aid, int64(param.Ps)); err != nil {
|
||
|
err = nil
|
||
|
} else if len(res) > 0 {
|
||
|
s.fmtContest(c, res, mid)
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
if act, err = s.MatchAct(c, param.Aid); err != nil {
|
||
|
log.Error("s.MatchAct error(%v)", err)
|
||
|
return
|
||
|
}
|
||
|
if act == nil || act.Sid <= 0 {
|
||
|
err = ecode.EsportsActNotExist
|
||
|
return
|
||
|
}
|
||
|
sids = []int64{act.Sid}
|
||
|
if mapSeasons, err = s.dao.EpSeasons(c, sids); err != nil {
|
||
|
log.Error("MatchAct s.dao.EpSeasons error(%v)", err)
|
||
|
return
|
||
|
}
|
||
|
season, ok = mapSeasons[act.Sid]
|
||
|
if !ok {
|
||
|
log.Error("s.ActTop sid(%d) not exists", act.Sid)
|
||
|
return
|
||
|
}
|
||
|
if param.Stime != "" {
|
||
|
sTime, _ = time.ParseInLocation("2006-01-02", param.Stime, time.Local)
|
||
|
if sTime.Unix() <= season.Stime {
|
||
|
param.Stime = time.Unix(season.Stime, 0).Format("2006-01-02 15:04:05")
|
||
|
} else {
|
||
|
sTime, _ = time.ParseInLocation("2006-01-02", param.Stime, time.Local)
|
||
|
param.Stime = time.Unix(sTime.Unix(), 0).Format("2006-01-02") + " 00:00:00"
|
||
|
}
|
||
|
} else {
|
||
|
param.Stime = time.Unix(season.Stime, 0).Format("2006-01-02 15:04:05")
|
||
|
}
|
||
|
if param.Etime != "" {
|
||
|
if season.Etime != 0 {
|
||
|
eTime, _ = time.ParseInLocation("2006-01-02", param.Etime, time.Local)
|
||
|
if eTime.Unix() >= season.Etime {
|
||
|
param.Etime = time.Unix(season.Etime, 0).Format("2006-01-02 15:04:05")
|
||
|
} else {
|
||
|
eTime, _ = time.ParseInLocation("2006-01-02", param.Etime, time.Local)
|
||
|
param.Etime = time.Unix(eTime.Unix(), 0).Format("2006-01-02") + " 23:59:59"
|
||
|
}
|
||
|
} else {
|
||
|
eTime, _ = time.ParseInLocation("2006-01-02", param.Etime, time.Local)
|
||
|
param.Etime = time.Unix(eTime.Unix(), 0).Format("2006-01-02") + " 23:59:59"
|
||
|
}
|
||
|
} else {
|
||
|
if season.Etime != 0 {
|
||
|
param.Etime = time.Unix(season.Etime, 0).Format("2006-01-02 15:04:05")
|
||
|
}
|
||
|
}
|
||
|
p := &model.ParamContest{
|
||
|
Mid: act.Mid,
|
||
|
Sids: []int64{act.Sid},
|
||
|
Sort: param.Sort,
|
||
|
Stime: param.Stime,
|
||
|
Etime: param.Etime,
|
||
|
Pn: param.Pn,
|
||
|
Ps: param.Ps,
|
||
|
}
|
||
|
if res, total, err = s.ContestCommon(c, mid, p); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if len(res) == 0 {
|
||
|
res = _emptContest
|
||
|
return
|
||
|
}
|
||
|
if isFirst {
|
||
|
s.cache.Do(c, func(c context.Context) {
|
||
|
s.dao.AddActTopCache(c, param.Aid, int64(param.Ps), res, total)
|
||
|
})
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// ActPoints act match point match
|
||
|
func (s *Service) ActPoints(c context.Context, mid int64, param *model.ParamActPoint) (res []*model.Contest, total int, err error) {
|
||
|
var (
|
||
|
act *model.Active
|
||
|
detail *model.ActiveDetail
|
||
|
)
|
||
|
isFirst := param.Pn == 1 && param.Sort == 0
|
||
|
if isFirst {
|
||
|
if res, total, err = s.dao.GetActPointsCache(c, param.Aid, param.MdID, int64(param.Ps)); err != nil {
|
||
|
err = nil
|
||
|
} else if len(res) > 0 {
|
||
|
s.fmtContest(c, res, mid)
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
if act, err = s.MatchAct(c, param.Aid); err != nil {
|
||
|
log.Error("s.dao.Active error(%v)", err)
|
||
|
return
|
||
|
}
|
||
|
if act == nil || act.Sid <= 0 {
|
||
|
err = ecode.EsportsActNotExist
|
||
|
return
|
||
|
}
|
||
|
p := &model.ParamContest{
|
||
|
Mid: act.Mid,
|
||
|
Sids: []int64{act.Sid},
|
||
|
Sort: param.Sort,
|
||
|
Pn: param.Pn,
|
||
|
Ps: param.Ps,
|
||
|
}
|
||
|
detail, err = s.dao.PActDetail(c, param.MdID)
|
||
|
if err != nil {
|
||
|
log.Error("s.dao.PActDetail error(%v)", err)
|
||
|
return
|
||
|
}
|
||
|
if detail != nil {
|
||
|
if detail.STime != 0 {
|
||
|
p.Stime = time.Unix(detail.STime, 0).Format("2006-01-02 15:04:05")
|
||
|
}
|
||
|
if detail.ETime != 0 {
|
||
|
p.Etime = time.Unix(detail.ETime, 0).Format("2006-01-02 15:04:05")
|
||
|
}
|
||
|
} else {
|
||
|
err = ecode.EsportsActPointNotExist
|
||
|
return
|
||
|
}
|
||
|
if res, total, err = s.ContestCommon(c, mid, p); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if len(res) == 0 {
|
||
|
res = _emptContest
|
||
|
return
|
||
|
}
|
||
|
if isFirst {
|
||
|
s.cache.Do(c, func(c context.Context) {
|
||
|
s.dao.AddActPointsCache(c, param.Aid, param.MdID, int64(param.Ps), res, total)
|
||
|
})
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
//contestTeam get contest team
|
||
|
func (s *Service) contestTeam(c context.Context, contests map[int64]*model.Contest, teams map[int64]*model.Filter) (list []*model.ContestInfo, err error) {
|
||
|
for _, v := range contests {
|
||
|
contest := &model.ContestInfo{Contest: v}
|
||
|
if v.HomeID > 0 {
|
||
|
if team, ok := teams[v.HomeID]; ok {
|
||
|
contest.HomeName = team.Title
|
||
|
contest.HomeTeam = team
|
||
|
} else {
|
||
|
contest.HomeName = ""
|
||
|
contest.HomeTeam = struct{}{}
|
||
|
}
|
||
|
} else {
|
||
|
contest.HomeName = ""
|
||
|
contest.HomeTeam = struct{}{}
|
||
|
}
|
||
|
if v.AwayID > 0 {
|
||
|
if team, ok := teams[v.AwayID]; ok {
|
||
|
contest.AwayName = team.Title
|
||
|
contest.AwayTeam = team
|
||
|
} else {
|
||
|
contest.AwayName = ""
|
||
|
contest.AwayTeam = struct{}{}
|
||
|
}
|
||
|
} else {
|
||
|
contest.AwayName = ""
|
||
|
contest.AwayTeam = struct{}{}
|
||
|
}
|
||
|
if v.SuccessTeam > 0 {
|
||
|
if team, ok := teams[v.SuccessTeam]; ok {
|
||
|
contest.SuccessName = team.Title
|
||
|
} else {
|
||
|
contest.SuccessName = ""
|
||
|
}
|
||
|
} else {
|
||
|
contest.SuccessName = ""
|
||
|
}
|
||
|
contest.Season = struct{}{}
|
||
|
contest.SuccessTeaminfo = struct{}{}
|
||
|
list = append(list, contest)
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
//TeamMap get team and map team id to team
|
||
|
func (s *Service) TeamMap(ctx context.Context) (res map[int64]*model.Filter, err error) {
|
||
|
var (
|
||
|
teams []*model.Filter
|
||
|
)
|
||
|
if teams, err = s.dao.Teams(ctx); err != nil {
|
||
|
log.Error("LoadKnockoutTree s.dao.Teams error(%v)", err)
|
||
|
return
|
||
|
}
|
||
|
res = make(map[int64]*model.Filter)
|
||
|
for _, v := range teams {
|
||
|
res[v.ID] = v
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// BuildKnockTree knock tree.
|
||
|
func (s *Service) BuildKnockTree(c context.Context) {
|
||
|
var (
|
||
|
trees []*model.Tree
|
||
|
sTree []*model.TreeList
|
||
|
mids []int64
|
||
|
contests map[int64]*model.Contest
|
||
|
cInfos []*model.ContestInfo
|
||
|
mapContests map[int64]*model.ContestInfo
|
||
|
treeList [][]*model.TreeList
|
||
|
err error
|
||
|
details []*model.ActiveDetail
|
||
|
teamMap map[int64]*model.Filter
|
||
|
)
|
||
|
if teamMap, err = s.TeamMap(c); err != nil {
|
||
|
log.Error("LoadKnockoutTree TeamMap error(%v)", err)
|
||
|
return
|
||
|
}
|
||
|
if details, err = s.dao.KDetails(c); err != nil {
|
||
|
log.Error("LoadKnockoutTree s.dao.KDetails error(%v)", err)
|
||
|
return
|
||
|
}
|
||
|
//build tree
|
||
|
for _, detail := range details {
|
||
|
if detail.Online == _downline {
|
||
|
//edit status; must add cache time
|
||
|
if s.dao.AddActKnockCacheTime(c, detail.ID); err != nil {
|
||
|
log.Error("LoadKnockoutTree s.dao.AddActKnockCacheTime error(%v)", err)
|
||
|
continue
|
||
|
}
|
||
|
} else {
|
||
|
treeList = _emptTreeList
|
||
|
sTree = make([]*model.TreeList, 0)
|
||
|
if trees, err = s.dao.Trees(c, detail.ID); err != nil {
|
||
|
log.Error("s.dao.Trees error(%v)", err)
|
||
|
return
|
||
|
}
|
||
|
for _, tree := range trees {
|
||
|
mids = append(mids, tree.Mid)
|
||
|
}
|
||
|
if len(mids) == 0 {
|
||
|
continue
|
||
|
} else {
|
||
|
count := len(mids)
|
||
|
if contests, err = s.dao.EpContests(c, mids); err != nil {
|
||
|
log.Error("s.dao.RawEpContests error(%v)", err)
|
||
|
continue
|
||
|
}
|
||
|
if cInfos, err = s.contestTeam(c, contests, teamMap); err != nil {
|
||
|
log.Error("s.contestTeam Error (%v)", err)
|
||
|
continue
|
||
|
}
|
||
|
mapContests = make(map[int64]*model.ContestInfo, count)
|
||
|
for _, info := range cInfos {
|
||
|
mapContests[info.ID] = info
|
||
|
}
|
||
|
for _, tree := range trees {
|
||
|
if tree.Pid == 0 {
|
||
|
if len(sTree) > 0 {
|
||
|
treeList = append(treeList, sTree)
|
||
|
}
|
||
|
sTree = nil
|
||
|
if cInfo, ok := mapContests[tree.Mid]; ok {
|
||
|
sTree = append(sTree, &model.TreeList{Tree: tree, ContestInfo: cInfo})
|
||
|
} else {
|
||
|
sTree = append(sTree, &model.TreeList{Tree: tree})
|
||
|
}
|
||
|
} else {
|
||
|
if cInfo, ok := mapContests[tree.Mid]; ok {
|
||
|
sTree = append(sTree, &model.TreeList{Tree: tree, ContestInfo: cInfo})
|
||
|
} else {
|
||
|
sTree = append(sTree, &model.TreeList{Tree: tree})
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if len(sTree) > 0 {
|
||
|
treeList = append(treeList, sTree)
|
||
|
}
|
||
|
if len(treeList) > 0 {
|
||
|
go s.dao.AddActKnockoutCache(context.Background(), detail.ID, treeList)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ActKnockout knockout tree
|
||
|
func (s *Service) ActKnockout(c context.Context, madID int64) (res [][]*model.TreeList, err error) {
|
||
|
if res, err = s.dao.GetActKnockoutCache(c, madID); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if len(res) == 0 {
|
||
|
res = _emptTreeList
|
||
|
err = ecode.EsportsActKnockNotExist
|
||
|
}
|
||
|
return
|
||
|
}
|