365 lines
9.0 KiB
Go
365 lines
9.0 KiB
Go
|
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
|
||
|
}
|