GamesPs.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. const axios = require('axios');
  2. const Logs = require('../libs/logs');
  3. const PS_IOR_KEYS = [
  4. ['0', 'ior_mh', 'ior_mn', 'ior_mc'],
  5. // ['0', 'ior_rh_05', 'ior_mn', 'ior_rc_05'],
  6. ['-1', 'ior_rh_15', 'ior_wmh_1', 'ior_rac_05'],
  7. ['-2', 'ior_rh_25', 'ior_wmh_2', 'ior_rac_15'],
  8. ['+1', 'ior_rah_05', 'ior_wmc_1', 'ior_rc_15'],
  9. ['+2', 'ior_rah_15', 'ior_wmc_2', 'ior_rc_25'],
  10. ];
  11. const BASE_URL = 'https://api.isthe.me/api/p';
  12. const IS_DEV = process.env.NODE_ENV == 'development';
  13. const GAMES = {
  14. Leagues: {},
  15. List: {},
  16. Baselist: {}
  17. };
  18. /**
  19. * 精确浮点数字
  20. * @param {number} number
  21. * @param {number} x
  22. * @returns {number}
  23. */
  24. const fixFloat = (number, x=2) => {
  25. return parseFloat(number.toFixed(x));
  26. }
  27. /**
  28. * 获取市场类型
  29. */
  30. const getMarketType = (mk) => {
  31. return mk == 0 ? 'early' : 'today';
  32. }
  33. /**
  34. * 同步联赛列表
  35. */
  36. const syncLeaguesList = ({ mk, leagues }) => {
  37. if (IS_DEV) {
  38. return Logs.out('syncLeaguesList', { mk, leagues });
  39. }
  40. axios.post(`${BASE_URL}/syncLeague`, { mk, leagues })
  41. .then(res => {
  42. Logs.out('syncLeaguesList', res.data);
  43. })
  44. .catch(err => {
  45. Logs.out('syncLeaguesList', err.message);
  46. });
  47. }
  48. /**
  49. * 更新联赛列表
  50. */
  51. const updateLeaguesList = ({ mk, leagues }) => {
  52. const leaguesList = GAMES.Leagues;
  53. if (JSON.stringify(leaguesList[mk]) != JSON.stringify(leagues)) {
  54. leaguesList[mk] = leagues;
  55. syncLeaguesList({ mk, leagues });
  56. return leagues.length;
  57. }
  58. return 0;
  59. }
  60. /**
  61. * 获取筛选过的联赛
  62. */
  63. const getFilteredLeagues = async (mk) => {
  64. return axios.get(`${BASE_URL}/getLeagueTast?mk=${mk}`)
  65. .then(res => {
  66. if (res.data.code == 0) {
  67. return res.data.data;
  68. }
  69. return Promise.reject(new Error(res.data.message));
  70. });
  71. }
  72. /**
  73. * 同步比赛列表到服务器
  74. */
  75. const syncGamesList = ({ platform, mk, games }) => {
  76. if (IS_DEV) {
  77. return Logs.out('syncGamesList', { platform, mk, games });
  78. }
  79. axios.post(`${BASE_URL}/syncGames`, { platform, mk, games })
  80. .then(res => {
  81. Logs.out('syncGamesList', { platform, mk, count: games.length }, res.data);
  82. })
  83. .catch(err => {
  84. Logs.out('syncGamesList', { platform, mk }, err.message);
  85. });
  86. }
  87. /**
  88. * 同步基准比赛列表
  89. */
  90. const syncBaseList = ({ marketType, games }) => {
  91. const baseList = GAMES.Baselist;
  92. if (!baseList[marketType]) {
  93. baseList[marketType] = games;
  94. }
  95. const newMap = new Map(games.map(item => [item.eventId, item]));
  96. // 删除不存在的项
  97. for (let i = baseList[marketType].length - 1; i >= 0; i--) {
  98. if (!newMap.has(baseList[marketType][i].eventId)) {
  99. baseList[marketType].splice(i, 1);
  100. }
  101. }
  102. // 添加或更新
  103. const oldIds = new Set(baseList[marketType].map(item => item.eventId));
  104. games.forEach(game => {
  105. if (!oldIds.has(game.eventId)) {
  106. // 添加新项
  107. baseList[marketType].push(game);
  108. }
  109. });
  110. }
  111. /**
  112. * 更新比赛列表
  113. */
  114. const updateGamesList = (({ platform, mk, games } = {}) => {
  115. return new Promise((resolve, reject) => {
  116. if (!platform || !games) {
  117. return reject(new Error('PLATFORM_GAMES_INVALID'));
  118. }
  119. const marketType = getMarketType(mk);
  120. syncGamesList({ platform, mk, games });
  121. if (platform == 'ps') {
  122. syncBaseList({ marketType, games });
  123. }
  124. resolve();
  125. });
  126. });
  127. /**
  128. * 提交盘口数据
  129. */
  130. const submitOdds = ({ platform, mk, games }) => {
  131. if (IS_DEV) {
  132. return Logs.out('syncOdds', { platform, mk, games });
  133. }
  134. axios.post(`${BASE_URL}/syncOdds`, { platform, mk, games})
  135. .then(res => {
  136. Logs.out('syncOdds', { platform, mk, count: games.length }, res.data);
  137. })
  138. .catch(err => {
  139. Logs.out('syncOdds', { platform, mk }, err.message);
  140. });
  141. }
  142. /**
  143. * 同步基准盘口
  144. */
  145. const syncBaseEvents = ({ mk, games, outrights }) => {
  146. const marketType = getMarketType(mk);
  147. const baseList = GAMES.Baselist;
  148. if (!baseList[marketType]) {
  149. return;
  150. }
  151. const baseMap = new Map(baseList[marketType].map(item => [item.eventId, item]));
  152. games?.forEach(game => {
  153. const { eventId, evtime, events } = game;
  154. const baseGame = baseMap.get(eventId);
  155. if (baseGame) {
  156. baseGame.evtime = evtime;
  157. baseGame.events = events;
  158. }
  159. });
  160. outrights?.forEach(outright => {
  161. const { parentId, sptime, special } = outright;
  162. const baseGame = baseMap.get(parentId);
  163. if (baseGame) {
  164. baseGame.sptime = sptime;
  165. baseGame.special = special;
  166. }
  167. });
  168. if (games?.length) {
  169. const gamesList = baseList[marketType]?.map(game => {
  170. const { evtime, events, sptime, special, ...gameInfo } = game;
  171. const expireTime = Date.now() - 15000;
  172. let odds = {};
  173. if (evtime > expireTime) {
  174. odds = { ...odds, ...events };
  175. }
  176. if (sptime > expireTime) {
  177. odds = { ...odds, ...special };
  178. }
  179. const matches = PS_IOR_KEYS.map(([label, ...keys]) => {
  180. const match = keys.map(key => ({
  181. key,
  182. value: odds[key] ?? 0
  183. }));
  184. return {
  185. label,
  186. match
  187. };
  188. }).filter(item => item.match.every(entry => entry.value !== 0));
  189. return { ...gameInfo, matches };
  190. });
  191. // Logs.out('baseList', baseList[marketType]);
  192. submitOdds({ platform: 'ps', mk, games: gamesList });
  193. }
  194. }
  195. /**
  196. * 更新比赛盘口
  197. */
  198. const updateGamesEvents = ({ platform, mk, games, outrights }) => {
  199. return new Promise((resolve, reject) => {
  200. if (!platform || (!games && !outrights)) {
  201. return reject(new Error('PLATFORM_GAMES_INVALID'));
  202. }
  203. if (platform == 'ps') {
  204. syncBaseEvents({ mk, games, outrights });
  205. }
  206. Logs.out('updateGamesEvents', { platform, mk, games, outrights });
  207. resolve();
  208. });
  209. }
  210. /**
  211. * 获取关联比赛
  212. */
  213. const getGamesRelation = async (mk) => {
  214. return axios.get(`${BASE_URL}/getGameTast?mk=${mk}`)
  215. .then(res => {
  216. if (res.data.code == 0) {
  217. return res.data.data;
  218. }
  219. return Promise.reject(new Error(res.data.message));
  220. });
  221. }
  222. /**
  223. * 同步比赛结果
  224. */
  225. const syncGamesResult = async (result) => {
  226. if (IS_DEV) {
  227. return Logs.out('updateGamesResult', result);
  228. }
  229. axios.post(`${BASE_URL}/syncMatchResult`, result)
  230. .then(res => {
  231. Logs.out('syncMatchResult', res.data);
  232. })
  233. .catch(err => {
  234. Logs.out('syncMatchResult', err.message);
  235. });
  236. }
  237. /**
  238. * 更新比赛结果
  239. */
  240. const updateGamesResult = (result) => {
  241. syncGamesResult(result);
  242. return Promise.resolve();
  243. }
  244. module.exports = {
  245. updateLeaguesList, getFilteredLeagues,
  246. updateGamesList, updateGamesEvents,
  247. getGamesRelation,
  248. updateGamesResult,
  249. }