const Logs = require('../libs/logs'); const eventsCombination = require('./trangleCalc'); const Request = { callbacks: {}, count: 0, } // const WIN_STEP = 15; // const SOL_FREEZ_TIME = 1000 * 30; const GLOBAL_DATA = { relationLength: 0, solutions: {}, }; const getDataFromParent = (type, callback) => { const id = ++Request.count; Request.callbacks[id] = callback; process.send({ method: 'get', id, type }); } const postDataToParent = (type, data) => { process.send({ method: 'post', type, data }); } process.on('message', (message) => { const { callbacks } = Request; const { method, id, type, data } = message; if (method == 'get' && id) { let responseData = null; // if (data == 'getSolution') { // responseData = Solution.get(); // } process.send({ type: 'response', id, data: responseData }); } else if (type == 'response' && id && callbacks[id]) { callbacks[id](data); delete callbacks[id]; } }); /** * 精确浮点数字 * @param {number} number * @param {number} x * @returns {number} */ const fixFloat = (number, x=2) => { return parseFloat(number.toFixed(x)); } const getGamesRelation = () => { return new Promise(resolve => { getDataFromParent('getGamesRelation', (relations) => { resolve(relations); }); }); } const getSolutionHistory = () => { return new Promise(resolve => { getDataFromParent('getSolutionHistory', (solutions) => { resolve(solutions); }); }); } const setSolution = (solutions) => { postDataToParent('setSolution', solutions); } const extractOdds = ({ evtime, events, sptime, special }) => { const expireTime = Date.now() - 15000; let odds = {}; if (evtime > expireTime) { odds = { ...odds, ...events }; } if (sptime > expireTime) { odds = { ...odds, ...special }; } return odds; } // const getOptimalOdds = (oddsMap) => { // const oddsInfo = {}; // Object.keys(oddsMap).forEach(platform => { // const odds = oddsMap[platform]; // Object.keys(odds).forEach(ior => { // const oddsValue = odds[ior]; // if (!oddsInfo[ior] || oddsInfo[ior]?.v < oddsValue) { // oddsInfo[ior] = { // p: platform, // v: oddsValue // } // } // }); // }); // return oddsInfo; // } const eventMatch = () => { Logs.out('start event match'); getGamesRelation() .then(relations => { const nowTime = Date.now(); relations = relations.filter(relaiton => { const expire = Object.values(relaiton.rel).find(event => event.timestamp <= nowTime); if (expire) { return false; } return true; }); const relationLength = relations.length; if (!relationLength) { if (GLOBAL_DATA.relationLength) { GLOBAL_DATA.relationLength = 0; Logs.out('relation list is empty'); } return []; } GLOBAL_DATA.relationLength = relationLength; const passableEvents = relations.map(({ id, rel }) => { const eventsMap = {}; const oddsMap = {}; Object.keys(rel).forEach(platform => { const { leagueName, teamHomeName, teamAwayName, timestamp, evtime, events, sptime, special } = rel[platform]; if (!events && !special) { return; } if (!eventsMap.info) { eventsMap.info = { leagueName, teamHomeName, teamAwayName, id, timestamp }; } const odds = extractOdds({ evtime, events, sptime, special }); Object.keys(odds).forEach(ior => { if (!oddsMap[ior]) { oddsMap[ior] = {}; } oddsMap[ior][platform] = odds[ior]; }); }); eventsMap.odds = oddsMap; return eventsMap; }); const solutions = eventsCombination(passableEvents); if (solutions?.length) { const solutionsHistory = GLOBAL_DATA.solutions; const updateIds = { add: [], update: [] } solutions.forEach(item => { const { sid, sol: { win_average } } = item; if (!solutionsHistory[sid]) { solutionsHistory[sid] = item; updateIds.add.push({ sid, win_average }); return; } const historyWinAverage = solutionsHistory[sid].sol.win_average; if (win_average != historyWinAverage) { solutionsHistory[sid] = item; updateIds.update.push({ sid, win_average, his_average: historyWinAverage, diff: fixFloat(win_average - historyWinAverage) }); return; } const { timestamp } = item; solutionsHistory[sid].timestamp = timestamp; }); if (updateIds.add.length || updateIds.update.length) { const solutionsList = Object.values(solutionsHistory).sort((a, b) => b.sol.win_average - a.sol.win_average); Logs.out('solutions history update', solutionsList, updateIds); } } }) .finally(() => { setTimeout(() => { eventMatch(); }, 2000); }); }; const solutionsCleanup = () => { const solutionsHistory = GLOBAL_DATA.solutions; Object.keys(solutionsHistory).forEach(sid => { const { timestamp } = solutionsHistory[sid]; const nowTime = Date.now(); if (nowTime - timestamp > 1000*60) { delete solutionsHistory[sid]; Logs.out('solution history timeout', sid); return; } const solution = solutionsHistory[sid]; const eventTime = solution.info.timestamp; if (nowTime > eventTime) { delete solutionsHistory[sid]; Logs.out('solution history expired', sid); } }); } setInterval(() => { solutionsCleanup(); }, 1000*30); eventMatch();