const { fork } = require('child_process'); const childOptions = process.env.NODE_ENV == 'development' ? { execArgv: ['--inspect=9228'] } : {}; const events_child = fork('./triangle/eventsMatch.js', [], childOptions); const Logs = require('../libs/logs'); const Relation = require('./Relation'); const Request = { callbacks: {}, count: 0, } const GAMES = { List: {}, Relations: {} }; const updateGamesList = (({ platform, type, games } = {}) => { return new Promise((resolve, reject) => { if (!platform || !games) { return reject(new Error('PLATFORM_GAMES_INVALID')); } const marketType = type == 0 ? 'early' : 'today'; let gamesList = games; if (platform == 'jc') { gamesList = []; const gamesEvents = []; const gamesOutrights = []; games.forEach(game => { const { eventId, events, evtime, special, sptime, ...gameInfo } = game; gamesList.push({ eventId, ...gameInfo }); gamesEvents.push({ eventId, events, evtime }); gamesOutrights.push({ parentId: eventId, special, sptime }); }); updateGamesEvents({ platform, games: gamesEvents, outrights: gamesOutrights }); } const timestamp = Date.now(); const GAMES_LIST = GAMES.List; if (!GAMES_LIST[platform]) { GAMES_LIST[platform] = {}; } if (!GAMES_LIST[platform][marketType]) { GAMES_LIST[platform][marketType] = { games: gamesList, timestamp }; return resolve({ add: gamesList.length, del: 0 }); } const oldGames = GAMES_LIST[platform][marketType].games; const newGames = gamesList; const updateCount = { add: 0, del: 0, }; const newMap = new Map(newGames.map(item => [item.eventId, item])); for (let i = oldGames.length - 1; i >= 0; i--) { if (!newMap.has(oldGames[i].eventId)) { oldGames.splice(i, 1); updateCount.del += 1; } } const oldIds = new Set(oldGames.map(item => item.eventId)); newGames.forEach(item => { if (!oldIds.has(item.eventId)) { oldGames.push(item); updateCount.add += 1; } }); GAMES_LIST[platform][marketType].timestamp = timestamp; resolve(updateCount); }); }); const updateGamesEvents = ({ platform, type, games, outrights }) => { return new Promise((resolve, reject) => { if (!platform || (!games && !outrights)) { return reject(new Error('PLATFORM_GAMES_INVALID')); } const oldGames = Object.values(GAMES.Relations).map(rel => rel[platform] ?? {}).flat(); if (!oldGames.length) { return resolve({ update: 0 }); } const updateCount = { update: 0 }; const oldMap = new Map(oldGames.map(item => [item.eventId, item])); games?.forEach(game => { const { eventId, evtime, events } = game; const oldGame = oldMap.get(eventId); if (oldGame) { oldGame.evtime = evtime; oldGame.events = events; updateCount.update ++; } }); outrights?.forEach(outright => { const { parentId, sptime, special } = outright; const oldGame = oldMap.get(parentId); if (oldGame) { oldGame.sptime = sptime; oldGame.special = special; updateCount.update ++; } }); resolve(updateCount); }); } const getGamesList = () => { const gamesListMap = {}; Object.keys(GAMES.List).forEach(platform => { const { today, early } = GAMES.List[platform]; const todayList = today?.games ?? []; const earlyList = early?.games ?? []; const timestamp_today = today?.timestamp ?? 0; const timestamp_early = early?.timestamp ?? 0; const timestamp = Math.max(timestamp_today, timestamp_early); gamesListMap[platform] = { games: [...todayList, ...earlyList], timestamp, timestamp_today, timestamp_early, } }); return gamesListMap; } const updateGamesRelation = async (relation) => { const { id, rel } = relation; return Relation.findOne({ id }) .then(result => { if (!result) { const gameRelation = new Relation(relation); return gameRelation.save(); } return Relation.updateOne({ id }, { $set: { rel } }); }) .then(result => { GAMES.Relations[id] = rel; return result; }); } const removeGamesRelation = async (id) => { if (!id) { return Promise.reject(new Error('ID_INVALID')); } return Relation.deleteOne({ id }) .then(result => { delete GAMES.Relations[id]; return result; }); } const getGamesRelation = async (listEvents) => { const relationIds = Object.keys(GAMES.Relations); if (listEvents) { return relationIds.map(id => { const rel = GAMES.Relations[id]; return { id, rel }; }); } return relationIds.map(id => { const rel = { ...GAMES.Relations[id] }; Object.keys(rel).forEach(platform => { const game = { ...rel[platform] }; delete game.events; delete game.evtime; delete game.special; delete game.sptime; rel[platform] = game; }); return { id, rel }; }); } const relationsCleanup = () => { const expireTime = Date.now() - 1000*60*5; getGamesRelation() .then(gamesRelation => { gamesRelation.forEach(item => { const { id, rel } = item; const expire = Object.values(rel).find(event => { return event.timestamp <= expireTime; }); if (expire) { Logs.out('relation cleanup', id); removeGamesRelation(id); } return true; }); }); } const relationSync = () => { Relation.find().then(relation => relation.forEach(item => { const { id, rel } = item.toObject(); GAMES.Relations[id] = rel; })); } const getDataFromChild = (type, callback) => { const id = ++Request.count; Request.callbacks[id] = callback; events_child.send({ method: 'get', id, type }); } events_child.on('message', async (message) => { const { callbacks } = Request; const { method, id, type, data } = message; if (method == 'get' && id) { let responseData = null; if (type == 'getGamesRelation') { responseData = await getGamesRelation(true); } else if (type == 'getSolutionHistory') { responseData = getSolutionHistory(); } events_child.send({ type: 'response', id, data: responseData }); } else if (method == 'post') { if (type == 'setSolution') { setSolution(data); } } else if (method == 'response' && id && callbacks[id]) { callbacks[id](data); delete callbacks[id]; } }); relationSync(); setInterval(() => { relationsCleanup(); }, 5000); module.exports = { updateGamesList, updateGamesEvents, getGamesList, updateGamesRelation, getGamesRelation, removeGamesRelation, }