go-common/app/interface/main/esports/service/service.go

365 lines
9.0 KiB
Go
Raw Normal View History

2019-04-22 10:49:16 +00:00
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
}