service.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. package service
  2. import (
  3. "context"
  4. "encoding/json"
  5. "math"
  6. "net/url"
  7. "strconv"
  8. "strings"
  9. "time"
  10. "go-common/app/interface/main/esports/conf"
  11. "go-common/app/interface/main/esports/dao"
  12. "go-common/app/interface/main/esports/model"
  13. arcclient "go-common/app/service/main/archive/api"
  14. favrpc "go-common/app/service/main/favorite/api/gorpc"
  15. "go-common/library/log"
  16. "go-common/library/sync/pipeline/fanout"
  17. "github.com/robfig/cron"
  18. )
  19. const (
  20. _perPage = 100
  21. _lolType = 1
  22. _dotaType = 2
  23. _firstPage = "1"
  24. _lolGame = "lol/games"
  25. _dotaGame = "dota2/games"
  26. _lolItems = "lol/items"
  27. _dotaItems = "dota2/items"
  28. _lolChampions = "lol/champions"
  29. _lolHeroes = "dota2/heroes"
  30. _lolSpells = "lol/spells"
  31. _dotaAbilities = "dota2/abilities"
  32. _lolPlayers = "lol/players"
  33. _dotaPlayers = "dota2/players"
  34. )
  35. // Service service struct.
  36. type Service struct {
  37. c *conf.Config
  38. dao *dao.Dao
  39. // rpc
  40. fav *favrpc.Service
  41. // cache proc
  42. cache *fanout.Fanout
  43. arcClient arcclient.ArchiveClient
  44. lolGameMap, dotaGameMap *model.SyncGame
  45. lolItemsMap, dotaItemsMap *model.SyncItem
  46. lolChampions *model.SyncChampion
  47. dotaHeroes *model.SyncHero
  48. lolSpells, dotaAbilities *model.SyncInfo
  49. lolPlayers, dotaPlayers *model.SyncInfo
  50. // cron
  51. cron *cron.Cron
  52. }
  53. // New new service.
  54. func New(c *conf.Config) *Service {
  55. s := &Service{
  56. c: c,
  57. dao: dao.New(c),
  58. fav: favrpc.New2(c.FavoriteRPC),
  59. cache: fanout.New("cache"),
  60. lolGameMap: &model.SyncGame{
  61. Data: make(map[int64][]*model.Game),
  62. },
  63. dotaGameMap: &model.SyncGame{
  64. Data: make(map[int64][]*model.Game),
  65. },
  66. lolItemsMap: &model.SyncItem{
  67. Data: make(map[int64]*model.Item),
  68. },
  69. dotaItemsMap: &model.SyncItem{
  70. Data: make(map[int64]*model.Item),
  71. },
  72. lolChampions: &model.SyncChampion{
  73. Data: make(map[int64]*model.Champion),
  74. },
  75. dotaHeroes: &model.SyncHero{
  76. Data: make(map[int64]*model.Hero),
  77. },
  78. lolSpells: &model.SyncInfo{
  79. Data: make(map[int64]*model.LdInfo),
  80. },
  81. dotaAbilities: &model.SyncInfo{
  82. Data: make(map[int64]*model.LdInfo),
  83. },
  84. lolPlayers: &model.SyncInfo{
  85. Data: make(map[int64]*model.LdInfo),
  86. },
  87. dotaPlayers: &model.SyncInfo{
  88. Data: make(map[int64]*model.LdInfo),
  89. },
  90. cron: cron.New(),
  91. }
  92. var err error
  93. if s.arcClient, err = arcclient.NewClient(c.ArcClient); err != nil {
  94. panic(err)
  95. }
  96. go s.loadKnockTreeCache()
  97. go s.loadLdGame()
  98. go s.createCron()
  99. return s
  100. }
  101. // Ping ping service.
  102. func (s *Service) Ping(c context.Context) (err error) {
  103. if err = s.dao.Ping(c); err != nil {
  104. log.Error("s.dao.Ping error(%v)", err)
  105. }
  106. return
  107. }
  108. // loadCache load cache
  109. func (s *Service) loadKnockTreeCache() {
  110. for {
  111. s.BuildKnockTree(context.Background())
  112. time.Sleep(time.Duration(conf.Conf.Rule.KnockTree))
  113. }
  114. }
  115. func (s *Service) loadLdGame() {
  116. var (
  117. contestDatas []*model.Contest
  118. err error
  119. )
  120. for {
  121. if contestDatas, err = s.dao.ContestDatas(context.Background()); err != nil {
  122. log.Error("loadLeida s.dao.ContestDatas error(%v)", err)
  123. time.Sleep(time.Second)
  124. continue
  125. }
  126. for _, data := range contestDatas {
  127. tmp := data
  128. go s.setGamesMap(tmp)
  129. }
  130. time.Sleep(time.Duration(conf.Conf.Leidata.AfterSleep))
  131. }
  132. }
  133. func (s *Service) createCron() {
  134. go s.lolPlayersCron()
  135. go s.dotaPlayersCron()
  136. go s.infoCron()
  137. s.cron.AddFunc(s.c.Leidata.LolPlayersCron, s.lolPlayersCron)
  138. s.cron.AddFunc(s.c.Leidata.DotaPlayersCron, s.dotaPlayersCron)
  139. s.cron.AddFunc(s.c.Leidata.InfoCron, s.infoCron)
  140. s.cron.Start()
  141. }
  142. func (s *Service) lolPlayersCron() {
  143. go s.loadLdPages(_lolPlayers)
  144. log.Info("createCron lolPlayersCron start")
  145. }
  146. func (s *Service) dotaPlayersCron() {
  147. go s.loadLdPages(_dotaPlayers)
  148. log.Info("createCron dotaPlayersCron start")
  149. }
  150. func (s *Service) infoCron() {
  151. go s.loadLdPages(_lolItems)
  152. go s.loadLdPages(_dotaItems)
  153. go s.loadLdPages(_lolSpells)
  154. go s.loadLdPages(_dotaAbilities)
  155. go s.loadLdPages(_lolChampions)
  156. go s.loadLdPages(_lolHeroes)
  157. log.Info("createCron infoCron start")
  158. }
  159. func (s *Service) setGamesMap(data *model.Contest) {
  160. var (
  161. err error
  162. params url.Values
  163. rs json.RawMessage
  164. games []*model.Game
  165. endTime time.Time
  166. isTime bool
  167. )
  168. params = url.Values{}
  169. params.Set("match_id", strconv.FormatInt(data.MatchID, 10))
  170. if data.Etime > 0 {
  171. endTime = time.Unix(data.Etime, 0).Add(time.Duration(s.c.Leidata.EndSleep))
  172. if time.Now().Unix() > endTime.Unix() {
  173. isTime = true
  174. }
  175. }
  176. if !isTime && data.Stime > 0 && time.Now().Unix() < data.Stime {
  177. isTime = true
  178. }
  179. if data.DataType == _lolType {
  180. if _, ok := s.lolGameMap.Data[data.MatchID]; ok && isTime {
  181. return
  182. }
  183. if rs, _, err = s.leida(params, _lolGame); err == nil {
  184. if err = json.Unmarshal(rs, &games); err == nil {
  185. s.lolGameMap.Lock()
  186. s.lolGameMap.Data[data.MatchID] = games
  187. s.lolGameMap.Unlock()
  188. }
  189. }
  190. } else if data.DataType == _dotaType {
  191. if _, ok := s.dotaGameMap.Data[data.MatchID]; ok && isTime {
  192. return
  193. }
  194. if rs, _, err = s.leida(params, _dotaGame); err == nil {
  195. if err = json.Unmarshal(rs, &games); err == nil {
  196. s.dotaGameMap.Lock()
  197. s.dotaGameMap.Data[data.MatchID] = games
  198. s.dotaGameMap.Unlock()
  199. }
  200. }
  201. }
  202. }
  203. func (s *Service) loadLdPages(tp string) {
  204. var (
  205. err error
  206. params url.Values
  207. count int
  208. )
  209. params = url.Values{}
  210. params.Set("page", _firstPage)
  211. params.Set("per_page", strconv.Itoa(_perPage))
  212. if count, err = s.setPages(tp, params); err != nil {
  213. return
  214. }
  215. for i := 2; i <= count; i++ {
  216. time.Sleep(time.Second)
  217. params.Set("page", strconv.Itoa(i))
  218. params.Set("per_page", strconv.Itoa(_perPage))
  219. s.setPages(tp, params)
  220. }
  221. }
  222. func (s *Service) setPages(tp string, params url.Values) (count int, err error) {
  223. var (
  224. rs json.RawMessage
  225. items []*model.Item
  226. infos []*model.LdInfo
  227. champions []*model.Champion
  228. heroes []*model.Hero
  229. )
  230. switch tp {
  231. case _lolItems:
  232. if rs, count, err = s.leida(params, _lolItems); err == nil {
  233. if err = json.Unmarshal(rs, &items); err == nil {
  234. for _, item := range items {
  235. s.lolItemsMap.Lock()
  236. s.lolItemsMap.Data[item.ID] = item
  237. s.lolItemsMap.Unlock()
  238. }
  239. }
  240. }
  241. case _dotaItems:
  242. if rs, count, err = s.leida(params, _dotaItems); err == nil {
  243. if err = json.Unmarshal(rs, &items); err == nil {
  244. for _, item := range items {
  245. s.dotaItemsMap.Lock()
  246. s.dotaItemsMap.Data[item.ID] = item
  247. s.dotaItemsMap.Unlock()
  248. }
  249. }
  250. }
  251. case _lolSpells:
  252. if rs, count, err = s.leida(params, _lolSpells); err == nil {
  253. if err = json.Unmarshal(rs, &infos); err == nil {
  254. for _, info := range infos {
  255. s.lolSpells.Lock()
  256. s.lolSpells.Data[info.ID] = info
  257. s.lolSpells.Unlock()
  258. }
  259. }
  260. }
  261. case _dotaAbilities:
  262. if rs, count, err = s.leida(params, _dotaAbilities); err == nil {
  263. if err = json.Unmarshal(rs, &infos); err == nil {
  264. for _, info := range infos {
  265. s.dotaAbilities.Lock()
  266. s.dotaAbilities.Data[info.ID] = info
  267. s.dotaAbilities.Unlock()
  268. }
  269. }
  270. }
  271. case _lolPlayers:
  272. if rs, count, err = s.leida(params, _lolPlayers); err == nil {
  273. if err = json.Unmarshal(rs, &infos); err == nil {
  274. for _, info := range infos {
  275. s.lolPlayers.Lock()
  276. s.lolPlayers.Data[info.ID] = info
  277. s.lolPlayers.Unlock()
  278. }
  279. }
  280. }
  281. case _dotaPlayers:
  282. if rs, count, err = s.leida(params, _dotaPlayers); err == nil {
  283. if err = json.Unmarshal(rs, &infos); err == nil {
  284. for _, info := range infos {
  285. s.dotaPlayers.Lock()
  286. s.dotaPlayers.Data[info.ID] = info
  287. s.dotaPlayers.Unlock()
  288. }
  289. }
  290. }
  291. case _lolChampions:
  292. if rs, count, err = s.leida(params, _lolChampions); err == nil {
  293. if err = json.Unmarshal(rs, &champions); err == nil {
  294. for _, champion := range champions {
  295. s.lolChampions.Lock()
  296. s.lolChampions.Data[champion.ID] = champion
  297. s.lolChampions.Unlock()
  298. }
  299. }
  300. }
  301. case _lolHeroes:
  302. if rs, count, err = s.leida(params, _lolHeroes); err == nil {
  303. if err = json.Unmarshal(rs, &heroes); err == nil {
  304. for _, hero := range heroes {
  305. s.dotaHeroes.Lock()
  306. s.dotaHeroes.Data[hero.ID] = hero
  307. s.dotaHeroes.Unlock()
  308. }
  309. }
  310. }
  311. }
  312. return
  313. }
  314. func (s *Service) leida(params url.Values, route string) (rs []byte, count int, err error) {
  315. var body, orginBody []byte
  316. params.Del("route")
  317. params.Set("key", s.c.Leidata.Key)
  318. url := s.c.Leidata.URL + "/" + route + "?" + params.Encode()
  319. for i := 0; i < s.c.Leidata.Retry; i++ {
  320. if body, err = s.dao.Leida(context.Background(), url); err != nil {
  321. time.Sleep(time.Second)
  322. continue
  323. }
  324. bodyStr := string(body[:])
  325. if bodyStr == "" {
  326. time.Sleep(time.Second)
  327. continue
  328. }
  329. rsPos := strings.Index(bodyStr, "[")
  330. if rsPos > -1 {
  331. orginBody = body
  332. body = []byte(bodyStr[rsPos:])
  333. } else {
  334. time.Sleep(time.Second)
  335. continue
  336. }
  337. rs = body
  338. totalPos := strings.Index(bodyStr, "X-Total:")
  339. if totalPos > 0 {
  340. s := string(orginBody[totalPos+9 : rsPos-4])
  341. if t, e := strconv.ParseFloat(s, 64); e == nil {
  342. count = int(math.Ceil(t / float64(_perPage)))
  343. }
  344. }
  345. break
  346. }
  347. if err != nil {
  348. log.Error("json.Unmarshal url(%s) body(%s) error(%v)", url, string(body), err)
  349. }
  350. return
  351. }