Partner.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import crypto from "crypto";
  2. import axios from "axios";
  3. import dotenv from 'dotenv';
  4. import path from "path";
  5. import { fileURLToPath } from "url";
  6. import { getData } from "../libs/cache.js";
  7. import Logs from "../libs/logs.js";
  8. dotenv.config();
  9. const __filename = fileURLToPath(import.meta.url);
  10. const __dirname = path.dirname(__filename);
  11. const IS_DEV = process.env.NODE_ENV == 'development';
  12. const PARTNER_DATA_FILE = path.join(__dirname, '../data/partner.json');
  13. /**
  14. * Partner API environment variables
  15. */
  16. const PARTNER_API_BASE = 'https://dev.api.ppai.win/api/p/gate';
  17. const { PARTNER_APP_ID, PARTNER_APP_KEY } = process.env;
  18. const PARTNER_DATA = {};
  19. /**
  20. * QBoss API environment variables
  21. */
  22. const QBOSS_API_BASE = IS_DEV ? 'https://cb.long.bid/api' : 'http://172.27.74.243/api';
  23. /**
  24. * axios instance
  25. */
  26. const axiosInstance = axios.create({
  27. proxy: false,
  28. });
  29. /**
  30. *
  31. */
  32. /**
  33. * 加载本地数据
  34. */
  35. const loadLocalData = async () => {
  36. const data = await getData(PARTNER_DATA_FILE);
  37. Object.assign(PARTNER_DATA, data);
  38. }
  39. loadLocalData().catch(error => {
  40. Logs.out('not load partner data', error.message);
  41. });
  42. /**
  43. * 生成SHA256
  44. */
  45. const generateSHA256 = (message) => {
  46. return crypto.createHash('sha256').update(message).digest('hex');
  47. }
  48. /**
  49. * 生成随机 nonce
  50. */
  51. const generateNonce = () => {
  52. return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
  53. }
  54. /**
  55. * 生成签名
  56. */
  57. const generateSignature = (appKey, action, timestamp, nonce) => {
  58. return generateSHA256(`${appKey}${action}${timestamp}${nonce}`);
  59. }
  60. /**
  61. * 获取时间戳 秒级
  62. */
  63. const getTimestamp = () => {
  64. return Math.floor(Date.now() / 1000);
  65. }
  66. /**
  67. * 时间窗口校验
  68. */
  69. const isTimestampValid = (timestamp, window=300) => {
  70. const now = getTimestamp();
  71. return Math.abs(now - timestamp) <= window;
  72. }
  73. /**
  74. * 请求Partner数据接口
  75. */
  76. export const requestData = async (action, data={}) => {
  77. const timestamp = getTimestamp();
  78. const nonce = generateNonce();
  79. const sign = generateSignature(PARTNER_APP_KEY, action, timestamp, nonce);
  80. const appid = PARTNER_APP_ID;
  81. const requestData = { action, appid, nonce, sign, timestamp };
  82. if (Object.keys(data).length > 0) {
  83. requestData.params = data;
  84. }
  85. return axiosInstance.post(PARTNER_API_BASE, requestData).then(res => res.data);
  86. }
  87. /**
  88. * 更新策略
  89. * @param {*} solutions
  90. * @returns
  91. */
  92. export const updateSolutions = async (solutions) => {
  93. if (process.env.NODE_ENV == 'development') {
  94. return Promise.resolve({ message: 'development mode' });
  95. }
  96. return requestData('opps.soccer', solutions);
  97. }
  98. /**
  99. * 获取关联比赛
  100. * @returns
  101. */
  102. export const getSoccerGames = async () => {
  103. return requestData('game.soccer');
  104. }
  105. /**
  106. * 获取QBoss赔率数据
  107. * @returns
  108. */
  109. export const getObossOdds = async () => {
  110. return axiosInstance.get(`${QBOSS_API_BASE}/pstery/get_games_relation`, {
  111. params: { lo: true, lp: true, hb: true, hh: true },
  112. }).then(res => res.data);
  113. }
  114. /**
  115. * 接收Partner数据
  116. */
  117. export const receivePartnerData = async (data) => {
  118. const { action, appid, nonce, sign, timestamp, params } = data;
  119. if (!isTimestampValid(timestamp)) {
  120. return Promise.reject(new Error('timestamp invalid'));
  121. }
  122. const partnerData = PARTNER_DATA[appid];
  123. if (!partnerData) {
  124. return Promise.reject(new Error('appid invalid'));
  125. }
  126. const newSign = generateSignature(partnerData.appkey, action, timestamp, nonce);
  127. if (newSign !== sign) {
  128. return Promise.reject(new Error('sign invalid'));
  129. }
  130. return Promise.resolve({ action, params });
  131. }
  132. export default { updateSolutions, getSoccerGames, getObossOdds, receivePartnerData };