flyzto 6 месяцев назад
Родитель
Сommit
e1bdbe12b4

+ 44 - 44
server/models/Games.js

@@ -37,14 +37,14 @@ const relationSchema = new Schema({
 
 const Relation = mongoose.model('Relation', relationSchema);
 
-const axios = require('axios');
-const { fork } = require('child_process');
-const calcTotalProfit = require('../triangle/totalProfitCalc');
-
 const childOptions = process.env.NODE_ENV == 'development' ? {
   execArgv: ['--inspect=9228']
 } : {};
-const events_child = fork('./triangle/eventsMatch.js', [], childOptions);
+// 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');
 
@@ -453,7 +453,7 @@ const solutionsCleanup = () => {
   });
 }
 
-const getTotalProfit = (sid1, sid2, gold_side_jc) => {
+const getTotalProfit = (sid1, sid2, gold_side_inner) => {
   const preSolution = GAMES.Solutions[sid1];
   const subSolution = GAMES.Solutions[sid2];
   const relId1 = preSolution?.info?.id;
@@ -470,49 +470,49 @@ const getTotalProfit = (sid1, sid2, gold_side_jc) => {
 
   const sol1 = preSolution?.sol;
   const sol2 = subSolution?.sol;
-  if (!sol1 || !sol2 || !gold_side_jc) {
+  if (!sol1 || !sol2 || !gold_side_inner) {
     return {};
   }
-  const profit = calcTotalProfit(sol1, sol2, gold_side_jc);
+  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 == 'setSolutions') {
-      setSolutions(data);
-    }
-  }
-  else if (method == 'response' && id && callbacks[id]) {
-    callbacks[id](data);
-    delete callbacks[id];
-  }
-});
+// 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 == 'setSolutions') {
+//       setSolutions(data);
+//     }
+//   }
+//   else if (method == 'response' && id && callbacks[id]) {
+//     callbacks[id](data);
+//     delete callbacks[id];
+//   }
+// });
 
 relationSync();
 setInterval(() => {

+ 177 - 5
server/models/GamesPs.js

@@ -1,5 +1,12 @@
 const axios = require('axios');
 const Logs = require('../libs/logs');
+const Setting = require('./Setting');
+
+const childOptions = process.env.NODE_ENV == 'development' ? {
+  execArgv: ['--inspect=9228']
+} : {};
+const { fork } = require('child_process');
+const events_child = fork('./triangle/eventsMatch.js', [], childOptions);
 
 const PS_IOR_KEYS = [
   ['0', 'ior_mh', 'ior_mn', 'ior_mc'],
@@ -16,9 +23,15 @@ const IS_DEV = process.env.NODE_ENV == 'development';
 const GAMES = {
   Leagues: {},
   List: {},
-  Baselist: {}
+  Baselist: {},
+  Relations: {},
 };
 
+const Request = {
+  callbacks: {},
+  count: 0,
+}
+
 /**
  * 精确浮点数字
  * @param {number} number
@@ -230,25 +243,137 @@ const updateGamesEvents = ({ platform, mk, games, outrights }) => {
       syncBaseEvents({ mk, games, outrights });
     }
 
-    Logs.outDev('updateGamesEvents', { platform, mk, games, outrights });
+    const relatedGames = Object.values(GAMES.Relations).map(item => item.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);
 
-    resolve();
   });
 }
 
 /**
  * 获取关联比赛
  */
-const getGamesRelation = async (mk) => {
+const fetchGamesRelation = async (mk='') => {
   return axios.get(`${BASE_URL}/getGameTast?mk=${mk}`)
   .then(res => {
     if (res.data.code == 0) {
-      return res.data.data;
+      const now = Date.now();
+      const gamesRelation = res.data.data?.filter(item => {
+        const timestamp = new Date(item.timestamp).getTime();
+        return timestamp > now;
+      }).map(item => {
+        const {
+          id, mk,
+          event_id: ps_event_id,
+          league_id: ps_league_id,
+          ob_event_id, ob_league_id,
+          hg_event_id, hg_league_id,
+        } = item;
+        const rel = {
+          ps: {
+            eventId: +ps_event_id,
+            leagueId: +ps_league_id
+          },
+          ob: ob_event_id ? {
+            eventId: +ob_event_id,
+            leagueId: +ob_league_id
+          } : null,
+          hg: hg_event_id ? {
+            eventId: +hg_event_id,
+            leagueId: +hg_league_id
+          } : null
+        };
+        return { id, mk, rel };
+      }) ?? [];
+      return gamesRelation;
     }
     return Promise.reject(new Error(res.data.message));
   });
 }
 
+const getGamesRelation = ({ mk, listEvents }) => {
+  const relations = Object.values(GAMES.Relations).filter(item => {
+    if (!mk) {
+      return true;
+    }
+    return item.mk == mk;
+  });
+  if (listEvents) {
+    return relations;
+  }
+  return relations.map(item => {
+    const { rel, ...relationInfo } = item;
+    Object.keys(rel).forEach(platform => {
+      const { events, evtime, sptime, special, ...gameInfo } = rel[platform];
+      rel[platform] = gameInfo;
+    });
+    return { ...relationInfo, rel };
+  });
+}
+
+/**
+ * 定时更新关联比赛列表
+ */
+const updateGamesRelation = () => {
+  fetchGamesRelation()
+  .then(res => {
+    const gamesRelation = res.flat();
+
+    gamesRelation.forEach(item => {
+      const { id } = item;
+      if (!GAMES.Relations[id]) {
+        GAMES.Relations[id] = item;
+      }
+    });
+
+    const relations = new Set(gamesRelation.map(item => +item.id));
+
+    Object.keys(GAMES.Relations).forEach(id => {
+      if (!relations.has(+id)) {
+        delete GAMES.Relations[id];
+      }
+    });
+
+  })
+  .catch(err => {
+    Logs.out('updateGamesRelation', err.message);
+  })
+  .finally(() => {
+    setTimeout(updateGamesRelation, 60000);
+  });
+}
+updateGamesRelation();
+
 /**
  * 同步比赛结果
  */
@@ -273,6 +398,53 @@ const updateGamesResult = (result) => {
   return Promise.resolve();
 }
 
+/**
+ * 获取后台设置
+ */
+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({ listEvents: true });
+      Logs.out('getGamesRelation', responseData);
+    }
+    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 == 'setSolutions') {
+      setSolutions(data);
+    }
+  }
+  else if (method == 'response' && id && callbacks[id]) {
+    callbacks[id](data);
+    delete callbacks[id];
+  }
+});
+
 module.exports = {
   updateLeaguesList, getFilteredLeagues,
   updateGamesList, updateGamesEvents,

+ 2 - 7
server/routes/pstery.js

@@ -61,13 +61,8 @@ router.get('/get_filtered_leagues', (req, res) => {
 // 获取关联列表
 router.get('/get_games_relation', (req, res) => {
   const { mk } = req.query;
-  Games.getGamesRelation(mk)
-  .then(gamesRelation => {
-    res.sendSuccess(gamesRelation);
-  })
-  .catch(err => {
-    res.badRequest(err.message);
-  });
+  const gamesRelation = Games.getGamesRelation({ mk });
+  res.sendSuccess(gamesRelation);
 });
 
 module.exports = router;

+ 2 - 2
server/routes/triangle.js

@@ -103,8 +103,8 @@ router.get('/get_solutions', authMiddleware, (req, res) => {
 
 // 计算总利润
 router.post('/calc_total_profit', authMiddleware, (req, res) => {
-  const { sid1, sid2, gold_side_jc } = req.body;
-  const totalProfit = Games.getTotalProfit(sid1, sid2, gold_side_jc);
+  const { sid1, sid2, gold_side_inner } = req.body;
+  const totalProfit = Games.getTotalProfit(sid1, sid2, gold_side_inner);
   res.sendSuccess(totalProfit);
 });
 

+ 38 - 38
server/triangle/totalProfitCalc.js

@@ -119,7 +119,7 @@ const HandicapCalc = function (data) {
 }
 
 const calcExternalHandicap = (data) => {
-  const { gold_side_jc: g, odds_side_a: a, odds_side_b: b, odds_side_m: c, jc_index: i, cross_type: t, win_target: w, loss_out_1 } = data;
+  const { gold_side_inner: g, odds_side_a: a, odds_side_b: b, odds_side_m: c, inner_index: i, cross_type: t, win_target: w, loss_out_1 } = data;
   const l = loss_out_1 ?? 0;
   const calc = new HandicapCalc({ i, g, a, b, c, w, l });
   const { x, y, z } = calc?.[t]() ?? {};
@@ -127,33 +127,33 @@ const calcExternalHandicap = (data) => {
     gold_side_a: fixFloat(x),
     gold_side_b: fixFloat(y),
     gold_side_m: fixFloat(z),
-    jc_index: i,
+    inner_index: i,
   }
 
 }
 
 const calcGoldsWithWinTarget = (data) => {
-  const { gold_side_jc, win_target, sol1, sol2 } = data;
+  const { gold_side_inner, win_target, sol1, sol2 } = data;
   const {
     gold_side_a: goldA1,
     gold_side_b: goldB1,
     gold_side_m: goldM1,
-    jc_index: jc_index_1
-  } = calcExternalHandicap({ ...sol1, gold_side_jc, win_target });
+    inner_index: inner_index_1
+  } = calcExternalHandicap({ ...sol1, gold_side_inner, win_target });
 
-  let loss_out_1 = 0, win_jc_1 = 0;
-  switch (jc_index_1) {
+  let loss_out_1 = 0, win_inner_1 = 0;
+  switch (inner_index_1) {
     case 0:
       loss_out_1 = goldB1 + goldM1;
-      win_jc_1 = gold_side_jc * (sol1.odds_side_a + 1);
+      win_inner_1 = gold_side_inner * (sol1.odds_side_a + 1);
       break;
     case 1:
       loss_out_1 = goldA1 + goldM1;
-      win_jc_1 = gold_side_jc * (sol1.odds_side_b + 1);
+      win_inner_1 = gold_side_inner * (sol1.odds_side_b + 1);
       break;
     case 2:
       loss_out_1 = goldA1 + goldB1;
-      win_jc_1 = gold_side_jc * (sol1.odds_side_m + 1)
+      win_inner_1 = gold_side_inner * (sol1.odds_side_m + 1)
       break;
   }
 
@@ -161,29 +161,29 @@ const calcGoldsWithWinTarget = (data) => {
     gold_side_a: goldA2,
     gold_side_b: goldB2,
     gold_side_m: goldM2,
-    jc_index: jc_index_2
-  } = calcExternalHandicap({ ...sol2, gold_side_jc, win_target, loss_out_1 });
+    inner_index: inner_index_2
+  } = calcExternalHandicap({ ...sol2, gold_side_inner, win_target, loss_out_1 });
 
-  let loss_out_2 = 0, win_jc_2 = 0, jc_base_key;
-  switch (jc_index_2) {
+  let loss_out_2 = 0, win_inner_2 = 0, inner_base_key;
+  switch (inner_index_2) {
     case 0:
-      jc_base_key = 'goldA2';
-      loss_out_2 = gold_side_jc +goldB2 + goldM2 + loss_out_1;
-      win_jc_2 = win_jc_1 * (sol2.odds_side_a + 1);
+      inner_base_key = 'goldA2';
+      loss_out_2 = gold_side_inner +goldB2 + goldM2 + loss_out_1;
+      win_inner_2 = win_inner_1 * (sol2.odds_side_a + 1);
       break;
     case 1:
-      jc_base_key = 'goldB2';
-      loss_out_2 = gold_side_jc + goldA2 + goldM2 + loss_out_1;
-      win_jc_2 = win_jc_1 * (sol2.odds_side_b + 1);
+      inner_base_key = 'goldB2';
+      loss_out_2 = gold_side_inner + goldA2 + goldM2 + loss_out_1;
+      win_inner_2 = win_inner_1 * (sol2.odds_side_b + 1);
       break;
     case 2:
-      jc_base_key = 'goldM2';
-      loss_out_2 = gold_side_jc + goldA2 + goldB2 + loss_out_1;
-      win_jc_2 = win_jc_1 * (sol2.odds_side_m + 1);
+      inner_base_key = 'goldM2';
+      loss_out_2 = gold_side_inner + goldA2 + goldB2 + loss_out_1;
+      win_inner_2 = win_inner_1 * (sol2.odds_side_m + 1);
       break;
   }
 
-  const win_jc = fixFloat(win_jc_2 - loss_out_2);
+  const win_inner = fixFloat(win_inner_2 - loss_out_2);
 
   const result = {
     goldA1,
@@ -192,37 +192,37 @@ const calcGoldsWithWinTarget = (data) => {
     goldA2,
     goldB2,
     goldM2,
-    win_jc,
-    jc_index_1,
-    jc_index_2,
-    jc_base: gold_side_jc,
+    win_inner,
+    inner_index_1,
+    inner_index_2,
+    inner_base: gold_side_inner,
   }
 
-  if (result[jc_base_key]) {
-    result[jc_base_key] = win_jc_1;
+  if (result[inner_base_key]) {
+    result[inner_base_key] = win_inner_1;
   }
 
   return result;
 }
 
-const calcTotalProfit = (sol1, sol2, gold_side_jc) => {
+const calcTotalProfit = (sol1, sol2, gold_side_inner) => {
 
   const winTarget1 = sol1.win_average;
   const winTarget2 = sol2.win_average;
   const winTarget = fixFloat(Math.min(winTarget1, winTarget2), 2);
 
-  const win1 = calcGoldsWithWinTarget({ gold_side_jc, win_target: winTarget1, sol1, sol2 })?.win_jc;
-  const win2 = calcGoldsWithWinTarget({ gold_side_jc, win_target: winTarget2, sol1, sol2 })?.win_jc;
-  const winJc = fixFloat(Math.max(win1, win2), 2);
+  const win1 = calcGoldsWithWinTarget({ gold_side_inner, win_target: winTarget1, sol1, sol2 })?.win_inner;
+  const win2 = calcGoldsWithWinTarget({ gold_side_inner, win_target: winTarget2, sol1, sol2 })?.win_inner;
+  const win_inner = fixFloat(Math.max(win1, win2), 2);
 
-  const start = Math.max(winTarget, winJc);
-  const end = Math.min(winTarget, winJc);
+  const start = Math.max(winTarget, win_inner);
+  const end = Math.min(winTarget, win_inner);
   const result = [];
 
   for (let i = start; i > end; i--) {
     const win_target = i;
-    const goldsInfo = calcGoldsWithWinTarget({ gold_side_jc, win_target, sol1, sol2 });
-    const win_diff = Math.abs(fixFloat(win_target - goldsInfo.win_jc));
+    const goldsInfo = calcGoldsWithWinTarget({ gold_side_inner, win_target, sol1, sol2 });
+    const win_diff = Math.abs(fixFloat(win_target - goldsInfo.win_inner));
     const lastResult = result.at(-1);
     if (!lastResult?.win_diff || win_diff < lastResult.win_diff) {
       result.push({ win_target: fixFloat(win_target), win_diff, ...goldsInfo });

+ 24 - 24
server/triangle/trangleCalc.js

@@ -17,7 +17,7 @@ function getOptimalSelections(data, combos) {
     let validOptions = [];
 
     for (let i = 0; i < 3; i++) {
-      const jcIndex = i;
+      const innerIndex = i;
       const selection = [];
       let isValid = true;
       for (let j = 0; j < 3; j++) {
@@ -28,20 +28,20 @@ function getOptimalSelections(data, combos) {
           isValid = false;
           break;
         }
-        if (j === jcIndex) {
-          if (!('jc' in item)) {
+        if (j === innerIndex) {
+          if (!('ps' in item)) {
             isValid = false;
             break;
           }
           selection.push({
             k: key,
-            p: 'jc',
-            v: item.jc,
+            p: 'ps',
+            v: item.ps,
             o: item,
           });
         }
         else {
-          const candidates = ['ps', 'ob'].filter((k) => k in item);
+          const candidates = ['ob', 'hg'].filter((k) => k in item);
           if (candidates.length === 0) {
             isValid = false;
             break;
@@ -98,7 +98,7 @@ const triangleProfitCalc = (goldsInfo, oddsOption) => {
     odds_side_m: c
   } = goldsInfo;
 
-  const { crossType, jcIndex } = oddsOption;
+  const { crossType, innerIndex } = oddsOption;
   /**
    * crossType:
    *  la: 全输
@@ -109,15 +109,15 @@ const triangleProfitCalc = (goldsInfo, oddsOption) => {
    *  la_wh_wa, la_dr_wa, la_lh_wa, lh_dr_wa, lh_lh_wa, la_la_wa
    */
 
-  let jc_rebate = 0;
-  if (jcIndex == 0) {
-    jc_rebate = x * innerRebateRatio;
+  let inner_rebate = 0;
+  if (innerIndex == 0) {
+    inner_rebate = x * innerRebateRatio;
   }
-  else if (jcIndex == 1) {
-    jc_rebate = y * innerRebateRatio;
+  else if (innerIndex == 1) {
+    inner_rebate = y * innerRebateRatio;
   }
-  else if (jcIndex == 2) {
-    jc_rebate = z * innerRebateRatio;
+  else if (innerIndex == 2) {
+    inner_rebate = z * innerRebateRatio;
   }
 
   let win_side_a = 0, win_side_b = 0, win_side_m = 0;
@@ -145,9 +145,9 @@ const triangleProfitCalc = (goldsInfo, oddsOption) => {
       break;
   }
 
-  win_side_a = fixFloat(win_side_a + jc_rebate);
-  win_side_b = fixFloat(win_side_b + jc_rebate);
-  win_side_m = fixFloat(win_side_m + jc_rebate);
+  win_side_a = fixFloat(win_side_a + inner_rebate);
+  win_side_b = fixFloat(win_side_b + inner_rebate);
+  win_side_m = fixFloat(win_side_m + inner_rebate);
   const win_average = fixFloat((win_side_a + win_side_b + win_side_m) / 3);
 
   return { win_side_a, win_side_b, win_side_m, win_average }
@@ -159,7 +159,7 @@ const triangleGoldCalc = (oddsInfo, oddsOption) => {
   if (!a || !b || !c) {
     return;
   }
-  const { crossType, jcIndex } = oddsOption;
+  const { crossType, innerIndex } = oddsOption;
   let x = innerDefaultAmount;
   let y = (a + 1) * x / (b + 1);
   let z;
@@ -186,13 +186,13 @@ const triangleGoldCalc = (oddsInfo, oddsOption) => {
       z = 0;
   }
 
-  if (jcIndex == 1) {
+  if (innerIndex == 1) {
     const scale = innerDefaultAmount / y;
     x = x * scale;
     y = innerDefaultAmount;
     z = z * scale;
   }
-  else if (jcIndex == 2) {
+  else if (innerIndex == 2) {
     const scale = innerDefaultAmount / z;
     x = x * scale;
     y = y * scale;
@@ -226,8 +226,8 @@ const eventSolutions = (oddsInfo, oddsOption) => {
     odds_side_m,
     win_average,
     cross_type: oddsOption.crossType,
-    jc_index: oddsOption.jcIndex,
-    jc_base: innerDefaultAmount,
+    inner_index: oddsOption.innerIndex,
+    inner_base: innerDefaultAmount,
   }
 }
 
@@ -253,7 +253,7 @@ const eventsCombination = (passableEvents, setting) => {
         const oddsSideA = iors[0];
         const oddsSideB = iors[1];
         const oddsSideM = iors[2];
-        const jcIndex = iors.findIndex(item => item.p == 'jc');
+        const innerIndex = iors.findIndex(item => item.p == 'ps');
         if (!oddsSideA || !oddsSideB || !oddsSideM) {
           return;
         }
@@ -263,7 +263,7 @@ const eventsCombination = (passableEvents, setting) => {
           odds_side_b: fixFloat(oddsSideB.v - 1),
           odds_side_m: fixFloat(oddsSideM.v - 1)
         };
-        const oddsOption = { crossType, jcIndex };
+        const oddsOption = { crossType, innerIndex };
         const sol = eventSolutions(oddsInfo, oddsOption);
         if (sol?.win_average > SETTING.minProfitAmount) {
           const id = info.id;