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.
364 lines
9.0 KiB
364 lines
9.0 KiB
package service |
|
|
|
import ( |
|
"context" |
|
"encoding/json" |
|
"math" |
|
"net/url" |
|
"strconv" |
|
"strings" |
|
"time" |
|
|
|
"go-common/app/interface/main/esports/conf" |
|
"go-common/app/interface/main/esports/dao" |
|
"go-common/app/interface/main/esports/model" |
|
arcclient "go-common/app/service/main/archive/api" |
|
favrpc "go-common/app/service/main/favorite/api/gorpc" |
|
"go-common/library/log" |
|
"go-common/library/sync/pipeline/fanout" |
|
|
|
"github.com/robfig/cron" |
|
) |
|
|
|
const ( |
|
_perPage = 100 |
|
_lolType = 1 |
|
_dotaType = 2 |
|
_firstPage = "1" |
|
_lolGame = "lol/games" |
|
_dotaGame = "dota2/games" |
|
_lolItems = "lol/items" |
|
_dotaItems = "dota2/items" |
|
_lolChampions = "lol/champions" |
|
_lolHeroes = "dota2/heroes" |
|
_lolSpells = "lol/spells" |
|
_dotaAbilities = "dota2/abilities" |
|
_lolPlayers = "lol/players" |
|
_dotaPlayers = "dota2/players" |
|
) |
|
|
|
// Service service struct. |
|
type Service struct { |
|
c *conf.Config |
|
dao *dao.Dao |
|
// rpc |
|
fav *favrpc.Service |
|
// cache proc |
|
cache *fanout.Fanout |
|
arcClient arcclient.ArchiveClient |
|
lolGameMap, dotaGameMap *model.SyncGame |
|
lolItemsMap, dotaItemsMap *model.SyncItem |
|
lolChampions *model.SyncChampion |
|
dotaHeroes *model.SyncHero |
|
lolSpells, dotaAbilities *model.SyncInfo |
|
lolPlayers, dotaPlayers *model.SyncInfo |
|
// cron |
|
cron *cron.Cron |
|
} |
|
|
|
// New new service. |
|
func New(c *conf.Config) *Service { |
|
s := &Service{ |
|
c: c, |
|
dao: dao.New(c), |
|
fav: favrpc.New2(c.FavoriteRPC), |
|
cache: fanout.New("cache"), |
|
lolGameMap: &model.SyncGame{ |
|
Data: make(map[int64][]*model.Game), |
|
}, |
|
dotaGameMap: &model.SyncGame{ |
|
Data: make(map[int64][]*model.Game), |
|
}, |
|
lolItemsMap: &model.SyncItem{ |
|
Data: make(map[int64]*model.Item), |
|
}, |
|
dotaItemsMap: &model.SyncItem{ |
|
Data: make(map[int64]*model.Item), |
|
}, |
|
lolChampions: &model.SyncChampion{ |
|
Data: make(map[int64]*model.Champion), |
|
}, |
|
dotaHeroes: &model.SyncHero{ |
|
Data: make(map[int64]*model.Hero), |
|
}, |
|
lolSpells: &model.SyncInfo{ |
|
Data: make(map[int64]*model.LdInfo), |
|
}, |
|
dotaAbilities: &model.SyncInfo{ |
|
Data: make(map[int64]*model.LdInfo), |
|
}, |
|
lolPlayers: &model.SyncInfo{ |
|
Data: make(map[int64]*model.LdInfo), |
|
}, |
|
dotaPlayers: &model.SyncInfo{ |
|
Data: make(map[int64]*model.LdInfo), |
|
}, |
|
cron: cron.New(), |
|
} |
|
var err error |
|
if s.arcClient, err = arcclient.NewClient(c.ArcClient); err != nil { |
|
panic(err) |
|
} |
|
go s.loadKnockTreeCache() |
|
go s.loadLdGame() |
|
go s.createCron() |
|
return s |
|
} |
|
|
|
// Ping ping service. |
|
func (s *Service) Ping(c context.Context) (err error) { |
|
if err = s.dao.Ping(c); err != nil { |
|
log.Error("s.dao.Ping error(%v)", err) |
|
} |
|
return |
|
} |
|
|
|
// loadCache load cache |
|
func (s *Service) loadKnockTreeCache() { |
|
for { |
|
s.BuildKnockTree(context.Background()) |
|
time.Sleep(time.Duration(conf.Conf.Rule.KnockTree)) |
|
} |
|
} |
|
|
|
func (s *Service) loadLdGame() { |
|
var ( |
|
contestDatas []*model.Contest |
|
err error |
|
) |
|
for { |
|
if contestDatas, err = s.dao.ContestDatas(context.Background()); err != nil { |
|
log.Error("loadLeida s.dao.ContestDatas error(%v)", err) |
|
time.Sleep(time.Second) |
|
continue |
|
} |
|
for _, data := range contestDatas { |
|
tmp := data |
|
go s.setGamesMap(tmp) |
|
} |
|
time.Sleep(time.Duration(conf.Conf.Leidata.AfterSleep)) |
|
} |
|
} |
|
func (s *Service) createCron() { |
|
go s.lolPlayersCron() |
|
go s.dotaPlayersCron() |
|
go s.infoCron() |
|
s.cron.AddFunc(s.c.Leidata.LolPlayersCron, s.lolPlayersCron) |
|
s.cron.AddFunc(s.c.Leidata.DotaPlayersCron, s.dotaPlayersCron) |
|
s.cron.AddFunc(s.c.Leidata.InfoCron, s.infoCron) |
|
s.cron.Start() |
|
} |
|
func (s *Service) lolPlayersCron() { |
|
go s.loadLdPages(_lolPlayers) |
|
log.Info("createCron lolPlayersCron start") |
|
} |
|
func (s *Service) dotaPlayersCron() { |
|
go s.loadLdPages(_dotaPlayers) |
|
log.Info("createCron dotaPlayersCron start") |
|
} |
|
func (s *Service) infoCron() { |
|
go s.loadLdPages(_lolItems) |
|
go s.loadLdPages(_dotaItems) |
|
go s.loadLdPages(_lolSpells) |
|
go s.loadLdPages(_dotaAbilities) |
|
go s.loadLdPages(_lolChampions) |
|
go s.loadLdPages(_lolHeroes) |
|
log.Info("createCron infoCron start") |
|
} |
|
|
|
func (s *Service) setGamesMap(data *model.Contest) { |
|
var ( |
|
err error |
|
params url.Values |
|
rs json.RawMessage |
|
games []*model.Game |
|
endTime time.Time |
|
isTime bool |
|
) |
|
params = url.Values{} |
|
params.Set("match_id", strconv.FormatInt(data.MatchID, 10)) |
|
if data.Etime > 0 { |
|
endTime = time.Unix(data.Etime, 0).Add(time.Duration(s.c.Leidata.EndSleep)) |
|
if time.Now().Unix() > endTime.Unix() { |
|
isTime = true |
|
} |
|
} |
|
if !isTime && data.Stime > 0 && time.Now().Unix() < data.Stime { |
|
isTime = true |
|
} |
|
if data.DataType == _lolType { |
|
if _, ok := s.lolGameMap.Data[data.MatchID]; ok && isTime { |
|
return |
|
} |
|
if rs, _, err = s.leida(params, _lolGame); err == nil { |
|
if err = json.Unmarshal(rs, &games); err == nil { |
|
s.lolGameMap.Lock() |
|
s.lolGameMap.Data[data.MatchID] = games |
|
s.lolGameMap.Unlock() |
|
} |
|
} |
|
} else if data.DataType == _dotaType { |
|
if _, ok := s.dotaGameMap.Data[data.MatchID]; ok && isTime { |
|
return |
|
} |
|
if rs, _, err = s.leida(params, _dotaGame); err == nil { |
|
if err = json.Unmarshal(rs, &games); err == nil { |
|
s.dotaGameMap.Lock() |
|
s.dotaGameMap.Data[data.MatchID] = games |
|
s.dotaGameMap.Unlock() |
|
} |
|
} |
|
} |
|
} |
|
|
|
func (s *Service) loadLdPages(tp string) { |
|
var ( |
|
err error |
|
params url.Values |
|
count int |
|
) |
|
params = url.Values{} |
|
params.Set("page", _firstPage) |
|
params.Set("per_page", strconv.Itoa(_perPage)) |
|
if count, err = s.setPages(tp, params); err != nil { |
|
return |
|
} |
|
for i := 2; i <= count; i++ { |
|
time.Sleep(time.Second) |
|
params.Set("page", strconv.Itoa(i)) |
|
params.Set("per_page", strconv.Itoa(_perPage)) |
|
s.setPages(tp, params) |
|
} |
|
} |
|
|
|
func (s *Service) setPages(tp string, params url.Values) (count int, err error) { |
|
var ( |
|
rs json.RawMessage |
|
items []*model.Item |
|
infos []*model.LdInfo |
|
champions []*model.Champion |
|
heroes []*model.Hero |
|
) |
|
switch tp { |
|
case _lolItems: |
|
if rs, count, err = s.leida(params, _lolItems); err == nil { |
|
if err = json.Unmarshal(rs, &items); err == nil { |
|
for _, item := range items { |
|
s.lolItemsMap.Lock() |
|
s.lolItemsMap.Data[item.ID] = item |
|
s.lolItemsMap.Unlock() |
|
} |
|
} |
|
} |
|
case _dotaItems: |
|
if rs, count, err = s.leida(params, _dotaItems); err == nil { |
|
if err = json.Unmarshal(rs, &items); err == nil { |
|
for _, item := range items { |
|
s.dotaItemsMap.Lock() |
|
s.dotaItemsMap.Data[item.ID] = item |
|
s.dotaItemsMap.Unlock() |
|
} |
|
} |
|
} |
|
case _lolSpells: |
|
if rs, count, err = s.leida(params, _lolSpells); err == nil { |
|
if err = json.Unmarshal(rs, &infos); err == nil { |
|
for _, info := range infos { |
|
s.lolSpells.Lock() |
|
s.lolSpells.Data[info.ID] = info |
|
s.lolSpells.Unlock() |
|
} |
|
} |
|
} |
|
case _dotaAbilities: |
|
if rs, count, err = s.leida(params, _dotaAbilities); err == nil { |
|
if err = json.Unmarshal(rs, &infos); err == nil { |
|
for _, info := range infos { |
|
s.dotaAbilities.Lock() |
|
s.dotaAbilities.Data[info.ID] = info |
|
s.dotaAbilities.Unlock() |
|
} |
|
} |
|
} |
|
case _lolPlayers: |
|
if rs, count, err = s.leida(params, _lolPlayers); err == nil { |
|
if err = json.Unmarshal(rs, &infos); err == nil { |
|
for _, info := range infos { |
|
s.lolPlayers.Lock() |
|
s.lolPlayers.Data[info.ID] = info |
|
s.lolPlayers.Unlock() |
|
} |
|
} |
|
} |
|
case _dotaPlayers: |
|
if rs, count, err = s.leida(params, _dotaPlayers); err == nil { |
|
if err = json.Unmarshal(rs, &infos); err == nil { |
|
for _, info := range infos { |
|
s.dotaPlayers.Lock() |
|
s.dotaPlayers.Data[info.ID] = info |
|
s.dotaPlayers.Unlock() |
|
} |
|
} |
|
} |
|
case _lolChampions: |
|
if rs, count, err = s.leida(params, _lolChampions); err == nil { |
|
if err = json.Unmarshal(rs, &champions); err == nil { |
|
for _, champion := range champions { |
|
s.lolChampions.Lock() |
|
s.lolChampions.Data[champion.ID] = champion |
|
s.lolChampions.Unlock() |
|
} |
|
} |
|
} |
|
case _lolHeroes: |
|
if rs, count, err = s.leida(params, _lolHeroes); err == nil { |
|
if err = json.Unmarshal(rs, &heroes); err == nil { |
|
for _, hero := range heroes { |
|
s.dotaHeroes.Lock() |
|
s.dotaHeroes.Data[hero.ID] = hero |
|
s.dotaHeroes.Unlock() |
|
} |
|
} |
|
} |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) leida(params url.Values, route string) (rs []byte, count int, err error) { |
|
var body, orginBody []byte |
|
params.Del("route") |
|
params.Set("key", s.c.Leidata.Key) |
|
url := s.c.Leidata.URL + "/" + route + "?" + params.Encode() |
|
for i := 0; i < s.c.Leidata.Retry; i++ { |
|
if body, err = s.dao.Leida(context.Background(), url); err != nil { |
|
time.Sleep(time.Second) |
|
continue |
|
} |
|
bodyStr := string(body[:]) |
|
if bodyStr == "" { |
|
time.Sleep(time.Second) |
|
continue |
|
} |
|
rsPos := strings.Index(bodyStr, "[") |
|
if rsPos > -1 { |
|
orginBody = body |
|
body = []byte(bodyStr[rsPos:]) |
|
} else { |
|
time.Sleep(time.Second) |
|
continue |
|
} |
|
rs = body |
|
totalPos := strings.Index(bodyStr, "X-Total:") |
|
if totalPos > 0 { |
|
s := string(orginBody[totalPos+9 : rsPos-4]) |
|
if t, e := strconv.ParseFloat(s, 64); e == nil { |
|
count = int(math.Ceil(t / float64(_perPage))) |
|
} |
|
} |
|
break |
|
} |
|
if err != nil { |
|
log.Error("json.Unmarshal url(%s) body(%s) error(%v)", url, string(body), err) |
|
} |
|
return |
|
}
|
|
|