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