import dotenv from 'dotenv'; import https from 'https'; import axios from "axios"; import { HttpsProxyAgent } from "https-proxy-agent"; import Logs from "./logs.js"; import { getAccountInfo } from "./getAccount.js"; dotenv.config(); const axiosDefaultOptions = { baseURL: "", url: "", method: "GET", headers: {}, params: {}, data: {}, timeout: 10000, }; const BaseURL = { pinnacle: "https://api.pinnacle888.com", ps3838: "https://api.ps3838.com", pstery: "http://127.0.0.1:9055", } const betPostPaths = new Set([ '/v4/bets/place', '/v4/bets/parlay', '/v4/bets/teaser', '/v4/bets/special', ]); const cloneJsonData = (data) => { if (data === undefined || data === null) { return data; } return JSON.parse(JSON.stringify(data)); } const toAccountCurrencyStake = (amount, accountInfo) => { const value = Number(amount); if (!Number.isFinite(value)) { return amount; } const currency = accountInfo?.currency?.toUpperCase() || 'USD'; if (currency === 'USD') { return Math.round(value); } const rate = Number(accountInfo?.currencyInfo?.rate); if (!Number.isFinite(rate) || rate <= 0) { const error = new Error(`currency rate is not ready: ${currency}`); error.cause = 503; error.data = { currency }; throw error; } return Math.round(value * rate); } const convertBetStakeToUsd = (data, accountInfo) => { if (!data || typeof data !== 'object') { return data; } const converted = cloneJsonData(data); const requests = Array.isArray(converted.bets) ? converted.bets : [converted]; requests.forEach(request => { if (!request || typeof request !== 'object') { return; } if (request.stake !== undefined) { request.stake = toAccountCurrencyStake(request.stake, accountInfo); } if (request.riskAmount !== undefined) { request.riskAmount = toAccountCurrencyStake(request.riskAmount, accountInfo); } }); return converted; } export const pinnacleRequest = async (options, channel) => { const accountInfo = getAccountInfo() ?? {}; const { username, password, localAddress, platform } = accountInfo; const { data, params, url, ...optionsRest } = options; if (!url || !channel && (!username || !password)) { throw new Error("url、username、password、channel is required"); } const requestData = !channel && optionsRest.method === 'POST' && betPostPaths.has(url) ? convertBetStakeToUsd(data, accountInfo) : data; Logs.outDev('pinnacle request', { url, channel, username, password, localAddress, platform }); const authHeader = channel ? `Basic ${channel}` : `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`; const axiosConfig = { ...axiosDefaultOptions, ...optionsRest, data: requestData, params, url, baseURL: BaseURL[platform] ?? BaseURL.pinnacle }; Object.assign(axiosConfig.headers, { "Authorization": authHeader, "Accept": "application/json", }); const proxy = process.env.NODE_HTTP_PROXY; if (proxy) { axiosConfig.proxy = false; axiosConfig.httpsAgent = new HttpsProxyAgent(proxy); // Logs.outDev('pinnacle request using proxy', axiosConfig.httpsAgent); } else if (localAddress) { axiosConfig.httpsAgent = new https.Agent({ localAddress }); } return axios(axiosConfig) .then(res => { // Logs.out('pinnacle request', url, axiosConfig, res.data); return res.data; }) .catch(err => { let user_name = ''; if (channel) { user_name = Buffer.from(channel, "base64").toString().split(':')[0]; } else { user_name = username; } const source = { url, params, username: user_name }; if (err?.response?.data) { const data = err.response.data; Object.assign(source, { data }); } err.source = source; return Promise.reject(err); }); } /** * Pinnacle API Get请求 * @param {*} url * @param {*} params * @returns */ export const pinnacleGet = async (url, params, channel) => { return pinnacleRequest({ url, params }, channel) } /** * Pinnacle API Post请求 * @param {*} url * @param {*} data * @returns */ export const pinnaclePost = async (url, data, channel) => { return pinnacleRequest({ url, method: 'POST', headers: { 'Content-Type': 'application/json', }, data }, channel); } export const getPsteryRelations = async (mk=-1) => { const axiosConfig = { baseURL: BaseURL.pstery, url: '/api/pstery/get_games_relation', method: 'GET', params: { mk, }, proxy: false, }; return axios(axiosConfig).then(res => res.data); } export const updateBaseEvents = async (data) => { const axiosConfig = { baseURL: BaseURL.pstery, url: '/api/pstery/update_base_events', method: 'POST', headers: { 'Content-Type': 'application/json', }, data: JSON.stringify(data), proxy: false, }; axios(axiosConfig).then(res => res.data) .then(() => { Logs.outDev('update base events success', data); }) .catch(err => { Logs.err('failed to update base events:', err.response?.data ?? err.message); }); } export const notifyException = async (message) => { const axiosConfig = { baseURL: BaseURL.pstery, url: '/api/pstery/notify_exception', method: 'POST', data: { message }, proxy: false, }; axios(axiosConfig).then(res => res.data) .then(() => { Logs.out('notify exception success'); }) .catch(err => { Logs.err('failed to notify exception:', err.message); }); }