|
|
@@ -1,531 +0,0 @@
|
|
|
-const mongoose = require('mongoose');
|
|
|
-const { Schema } = mongoose;
|
|
|
-
|
|
|
-const gameSchema = new Schema({
|
|
|
- leagueId: { type: Number, required: true },
|
|
|
- eventId: { type: Number, required: true },
|
|
|
- leagueName: { type: String, required: true },
|
|
|
- teamHomeName: { type: String, required: true },
|
|
|
- teamAwayName: { type: String, required: true },
|
|
|
- timestamp: { type: Number, required: true },
|
|
|
- matchNumStr: { type: String, required: false }
|
|
|
-}, { _id: false });
|
|
|
-
|
|
|
-const relSchema = new Schema({
|
|
|
- jc: { type: gameSchema },
|
|
|
- ps: { type: gameSchema },
|
|
|
- ob: { type: gameSchema },
|
|
|
-}, { _id: false });
|
|
|
-
|
|
|
-const relationSchema = new Schema({
|
|
|
- id: { type: Number, required: true },
|
|
|
- rel: { type: relSchema, required: true },
|
|
|
-}, {
|
|
|
- toJSON: {
|
|
|
- transform(doc, ret) {
|
|
|
- delete ret._id;
|
|
|
- delete ret.__v;
|
|
|
- }
|
|
|
- },
|
|
|
- toObject: {
|
|
|
- transform(doc, ret) {
|
|
|
- delete ret._id;
|
|
|
- delete ret.__v;
|
|
|
- }
|
|
|
- }
|
|
|
-});
|
|
|
-
|
|
|
-const Relation = mongoose.model('Relation', relationSchema);
|
|
|
-
|
|
|
-const childOptions = process.env.NODE_ENV == 'development' ? {
|
|
|
- execArgv: ['--inspect=9228']
|
|
|
-} : {};
|
|
|
-// const { fork } = require('child_process');
|
|
|
-// const events_child = fork('./triangle/eventsMatch.js', [], childOptions);
|
|
|
-
|
|
|
-const axios = require('axios');
|
|
|
-const calcTotalProfit = require('../triangle/totalProfitCalc');
|
|
|
-
|
|
|
-const Logs = require('../libs/logs');
|
|
|
-
|
|
|
-const Setting = require('./Setting');
|
|
|
-
|
|
|
-const Request = {
|
|
|
- callbacks: {},
|
|
|
- count: 0,
|
|
|
-}
|
|
|
-
|
|
|
-const GAMES = {
|
|
|
- Leagues: {},
|
|
|
- List: {},
|
|
|
- Relations: {},
|
|
|
- Solutions: {},
|
|
|
-};
|
|
|
-
|
|
|
-/**
|
|
|
- * 精确浮点数字
|
|
|
- * @param {number} number
|
|
|
- * @param {number} x
|
|
|
- * @returns {number}
|
|
|
- */
|
|
|
-const fixFloat = (number, x=2) => {
|
|
|
- return parseFloat(number.toFixed(x));
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * 更新联赛列表
|
|
|
- */
|
|
|
-const syncLeaguesList = ({ mk, leagues }) => {
|
|
|
- axios.post('https://api.isthe.me/api/p/syncLeague', { mk, leagues })
|
|
|
- .then(res => {
|
|
|
- Logs.out('syncLeaguesList', res.data);
|
|
|
- })
|
|
|
- .catch(err => {
|
|
|
- Logs.out('syncLeaguesList', err.message);
|
|
|
- });
|
|
|
-}
|
|
|
-const updateLeaguesList = ({ mk, leagues }) => {
|
|
|
- const leaguesList = GAMES.Leagues;
|
|
|
- if (JSON.stringify(leaguesList[mk]) != JSON.stringify(leagues)) {
|
|
|
- leaguesList[mk] = leagues;
|
|
|
- syncLeaguesList({ mk, leagues });
|
|
|
- return leagues.length;
|
|
|
- }
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * 获取筛选过的联赛
|
|
|
- */
|
|
|
-const getFilteredLeagues = async (mk) => {
|
|
|
- return axios.get(`https://api.isthe.me/api/p/getLeagueTast?mk=${mk}`)
|
|
|
- .then(res => {
|
|
|
- if (res.data.code == 0) {
|
|
|
- return res.data.data;
|
|
|
- }
|
|
|
- return Promise.reject(new Error(res.data.message));
|
|
|
- });
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * 更新比赛列表
|
|
|
- */
|
|
|
-const syncGamesList = ({ platform, mk, games }) => {
|
|
|
- axios.post('https://api.isthe.me/api/p/syncGames', { platform, mk, games })
|
|
|
- .then(res => {
|
|
|
- Logs.out('syncGamesList', res.data);
|
|
|
- })
|
|
|
- .catch(err => {
|
|
|
- Logs.out('syncGamesList', err.message);
|
|
|
- });
|
|
|
-}
|
|
|
-const updateGamesList = (({ platform, mk, games } = {}) => {
|
|
|
- syncGamesList({ platform, mk, games });
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
- if (!platform || !games) {
|
|
|
- return reject(new Error('PLATFORM_GAMES_INVALID'));
|
|
|
- }
|
|
|
-
|
|
|
- const marketType = mk == 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));
|
|
|
- const relatedGames = Object.values(GAMES.Relations).map(rel => rel[platform] ?? {});
|
|
|
- const relatedMap = new Map(relatedGames.map(item => [item.eventId, item]));
|
|
|
- newGames.forEach(item => {
|
|
|
- if (!oldIds.has(item.eventId)) {
|
|
|
- oldGames.push(item);
|
|
|
- updateCount.add += 1;
|
|
|
- }
|
|
|
- if (relatedMap.has(item.eventId)) {
|
|
|
- const relatedGame = relatedMap.get(item.eventId);
|
|
|
- relatedGame.mk = mk;
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- GAMES_LIST[platform][marketType].timestamp = timestamp;
|
|
|
-
|
|
|
- resolve(updateCount);
|
|
|
- });
|
|
|
-});
|
|
|
-
|
|
|
-/**
|
|
|
- * 更新比赛盘口
|
|
|
- */
|
|
|
-const updateGamesEvents = ({ platform, mk, games, outrights }) => {
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
- if (!platform || (!games && !outrights)) {
|
|
|
- return reject(new Error('PLATFORM_GAMES_INVALID'));
|
|
|
- }
|
|
|
-
|
|
|
- const relatedGames = Object.values(GAMES.Relations).map(rel => rel[platform] ?? {});
|
|
|
-
|
|
|
- if (!relatedGames.length) {
|
|
|
- return resolve({ update: 0 });
|
|
|
- }
|
|
|
-
|
|
|
- const updateCount = {
|
|
|
- update: 0
|
|
|
- };
|
|
|
-
|
|
|
- const relatedMap = new Map(relatedGames.map(item => [item.eventId, item]));
|
|
|
-
|
|
|
- games?.forEach(game => {
|
|
|
- const { eventId, evtime, events } = game;
|
|
|
- const relatedGame = relatedMap.get(eventId);
|
|
|
- if (relatedGame) {
|
|
|
- relatedGame.evtime = evtime;
|
|
|
- relatedGame.events = events;
|
|
|
- updateCount.update ++;
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- outrights?.forEach(outright => {
|
|
|
- const { parentId, sptime, special } = outright;
|
|
|
- const relatedGame = relatedMap.get(parentId);
|
|
|
- if (relatedGame) {
|
|
|
- relatedGame.sptime = sptime;
|
|
|
- relatedGame.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 getGamesEvents = ({ platform, relIds = [] } = {}) => {
|
|
|
- const idSet = new Set(relIds);
|
|
|
- const relations = { ...GAMES.Relations };
|
|
|
- Object.keys(relations).forEach(id => {
|
|
|
- if (idSet.size && !idSet.has(id)) {
|
|
|
- delete relations[id];
|
|
|
- }
|
|
|
- });
|
|
|
- if (platform) {
|
|
|
- return Object.values(relations).map(rel => rel[platform] ?? {});
|
|
|
- }
|
|
|
- const gamesEvents = {};
|
|
|
- Object.values(relations).forEach(rel => {
|
|
|
- Object.keys(rel).forEach(platform => {
|
|
|
- const game = rel[platform] ?? {};
|
|
|
- const { eventId, events, special } = game;
|
|
|
- if (!gamesEvents[platform]) {
|
|
|
- gamesEvents[platform] = {};
|
|
|
- }
|
|
|
- gamesEvents[platform][eventId] = { ...events, ...special };
|
|
|
- });
|
|
|
- });
|
|
|
- return gamesEvents;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * 更新关联比赛
|
|
|
- */
|
|
|
-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 = (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;
|
|
|
- const gamesRelation = getGamesRelation();
|
|
|
- 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 updateSolutions = (solutions) => {
|
|
|
- if (solutions?.length) {
|
|
|
- const solutionsHistory = GAMES.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.outDev('solutions history update', JSON.stringify(solutionsList, null, 2), JSON.stringify(updateIds, null, 2));
|
|
|
- // }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * 获取中单方案
|
|
|
- */
|
|
|
-const getSolutions = async () => {
|
|
|
- const solutionsList = Object.values(GAMES.Solutions);
|
|
|
- const relIds = solutionsList.map(item => item.info.id);
|
|
|
- const gamesEvents = getGamesEvents({ relIds });
|
|
|
- const gamesRelations = getGamesRelation();
|
|
|
- const relationsMap = new Map(gamesRelations.map(item => [item.id, item.rel]));
|
|
|
- const solutions = solutionsList.sort((a, b) => b.sol.win_average - a.sol.win_average).map(item => {
|
|
|
- const { info: { id } } = item;
|
|
|
- const relation = relationsMap.get(id);
|
|
|
- return {
|
|
|
- ...item,
|
|
|
- info: { id, ...relation }
|
|
|
- }
|
|
|
- });
|
|
|
- return { solutions, gamesEvents };
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * 清理中单方案
|
|
|
- */
|
|
|
-const solutionsCleanup = () => {
|
|
|
- const solutionsHistory = GAMES.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);
|
|
|
- }
|
|
|
- });
|
|
|
-}
|
|
|
-
|
|
|
-const getTotalProfit = (sid1, sid2, gold_side_inner) => {
|
|
|
- const preSolution = GAMES.Solutions[sid1];
|
|
|
- const subSolution = GAMES.Solutions[sid2];
|
|
|
- const relId1 = preSolution?.info?.id;
|
|
|
- const relId2 = subSolution?.info?.id;
|
|
|
- const relIds = [relId1, relId2];
|
|
|
- const gamesEvents = getGamesEvents({ relIds });
|
|
|
-
|
|
|
- const gamesRelations = getGamesRelation();
|
|
|
- const relationsMap = new Map(gamesRelations.map(item => [item.id, item.rel]));
|
|
|
- const preRelation = relationsMap.get(relId1);
|
|
|
- const subRelation = relationsMap.get(relId2);
|
|
|
- preSolution.info = { id: relId1, ...preRelation };
|
|
|
- subSolution.info = { id: relId2, ...subRelation };
|
|
|
-
|
|
|
- const sol1 = preSolution?.sol;
|
|
|
- const sol2 = subSolution?.sol;
|
|
|
- if (!sol1 || !sol2 || !gold_side_inner) {
|
|
|
- return {};
|
|
|
- }
|
|
|
- const profit = calcTotalProfit(sol1, sol2, gold_side_inner);
|
|
|
- return { profit, preSolution, subSolution, gamesEvents };
|
|
|
-}
|
|
|
-
|
|
|
-// const getSetting = async () => {
|
|
|
-// return Setting.get();
|
|
|
-// }
|
|
|
-
|
|
|
-// 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 = getGamesRelation(true);
|
|
|
-// }
|
|
|
-// else if (type == 'getSetting') {
|
|
|
-// responseData = await getSetting();
|
|
|
-// }
|
|
|
-// // else if (type == 'getSolutionHistory') {
|
|
|
-// // responseData = getSolutionHistory();
|
|
|
-// // }
|
|
|
-// events_child.send({ type: 'response', id, data: responseData });
|
|
|
-// }
|
|
|
-// else if (method == 'post') {
|
|
|
-// if (type == 'updateSolutions') {
|
|
|
-// updateSolutions(data);
|
|
|
-// }
|
|
|
-// }
|
|
|
-// else if (method == 'response' && id && callbacks[id]) {
|
|
|
-// callbacks[id](data);
|
|
|
-// delete callbacks[id];
|
|
|
-// }
|
|
|
-// });
|
|
|
-
|
|
|
-relationSync();
|
|
|
-setInterval(() => {
|
|
|
- relationsCleanup();
|
|
|
-}, 5000);
|
|
|
-
|
|
|
-setInterval(() => {
|
|
|
- solutionsCleanup();
|
|
|
-}, 1000*30);
|
|
|
-
|
|
|
-module.exports = {
|
|
|
- updateLeaguesList, getFilteredLeagues,
|
|
|
- updateGamesList, updateGamesEvents, getGamesList,
|
|
|
- updateGamesRelation, getGamesRelation, removeGamesRelation,
|
|
|
- getGamesEvents, getSolutions, getTotalProfit,
|
|
|
-}
|