const axios = require('axios'); const fs = require('fs'); const path = require('path'); const config = require('../config/index'); class RemoteConfig { constructor() { this.data = null; // 使用 Gitee/GitHub Raw URL if (config.remoteConfig.configUrl && config.remoteConfig.configUrl.startsWith('http')) { this.url = config.remoteConfig.configUrl; //console.log('RemoteConfig: Using direct configUrl:', this.url); } else { this.url = ""; console.warn('RemoteConfig: Missing configUrl.'); } this.timer = null; this.localPath = path.join(__dirname, '../config/update_jsonv2.txt'); this.updateCallbacks = []; } onUpdate(callback) { if (typeof callback === 'function') { this.updateCallbacks.push(callback); } } triggerUpdate() { this.updateCallbacks.forEach(cb => { try { cb(); } catch (e) { console.error('Error in remote config update callback:', e); } }); } start() { this.fetchConfig(); // 定时更新 const interval = config.remoteConfig.interval || 30000; this.timer = setInterval(() => { this.fetchConfig(); }, interval); } async fetchConfig() { try { // 1. 尝试从远程 URL 获取配置 // console.log('Fetching remote config from:', this.url); const response = await axios.get(this.url + "?" + Date.now(), { timeout: 5000 }); // 添加超时控制 if (response.data) { this.parseData(response.data); // console.log('Remote config updated from URL.'); // 可选:更新成功后,可以把最新的配置写入本地文件作为缓存 // fs.writeFileSync(this.localPath, typeof response.data === 'string' ? response.data : JSON.stringify(response.data, null, 4)); } } catch (error) { console.error('Error fetching remote config:', error.message); // 2. 远程获取失败,降级读取本地文件 if (fs.existsSync(this.localPath)) { try { const fileContent = fs.readFileSync(this.localPath, 'utf-8'); this.parseData(fileContent); //console.log('Fallback: Loaded config from local file:', this.localPath); } catch(e) { console.error('Fallback failed:', e); } } else { console.warn('No local config file found for fallback.'); } } } parseData(data) { let parsedData = null; if (typeof data === 'string') { try { parsedData = JSON.parse(data.trim()); } catch (e) { console.error('Failed to parse config JSON:', e); } } else { parsedData = data; } if (parsedData) { this.data = parsedData; this.triggerUpdate(); } } getParaValue(paraname, agentid, gameid, channelid, marketid) { let paravalue = null; if (!this.data) { return paravalue; } // 1. Root level if (this.data[paraname]) { paravalue = this.data[paraname]; } // Helper to find item in list and update paravalue const findAndCheck = (list, key, value) => { if (!list || !Array.isArray(list)) return null; for (const item of list) { if (item[key] == value) { if (item[paraname]) { paravalue = item[paraname]; } return item; } } return null; }; // 2. Agent level const agent = findAndCheck(this.data.agentlist, 'agentid', agentid); if (!agent) return paravalue; // 3. Game level const game = findAndCheck(agent.gamelist, 'gameid', gameid); if (!game) return paravalue; // 4. Channel level const channel = findAndCheck(game.channellist, 'channelid', channelid); if (!channel) return paravalue; // 5. Market level const market = findAndCheck(channel.marketlist, 'marketid', marketid); return paravalue; } // 获取游戏列表_下载页面 getGameListDownHtml(agentid, channelid) { const gamelist = []; if (!this.data || !this.data.agentlist) { return gamelist; } for (const agent of this.data.agentlist) { if (agent.agentid == agentid) { if (agent.gamelist) { for (const game of agent.gamelist) { const o_game = { name: game.gamename, image: game.game_down_image, state: game.game_down_state, memo: game.game_down_memo }; if (game.channellist) { for (const channel of game.channellist) { if (channel.channelid == channelid) { const _ios_marketid = channel.ios_defdownload_marketid; const _and_marketid = channel.and_defdownload_marketid; if (channel.marketlist) { for (const market of channel.marketlist) { if (market.marketid == _ios_marketid) { o_game.ios_down = market.app_download; o_game.ios_size = market.app_size; o_game.ios_marketid = _ios_marketid; } if (market.marketid == _and_marketid) { o_game.android_down = market.app_download; o_game.android_size = market.app_size; } } } if (o_game.ios_down && o_game.android_down) { gamelist.push(o_game); } break; } } } } } break; } } return gamelist; } // 获取游戏列表_游戏大厅 getGameListGameHall(agentid, channelid, marketid) { const gamelist = []; if (!this.data || !this.data.agentlist) { return gamelist; } for (const agent of this.data.agentlist) { if (agent.agentid == agentid) { if (agent.gamelist) { for (const game of agent.gamelist) { if (game.gameid != "G2hw0ubng0zcoI0r4mx3H2yr4GejidwO") { const o_game = { gameid: game.gameid, gamename: game.gamename, gamedir: game.game_hall_dir, gameimage: game.game_hall_image, gameversion: game.game_version, gamezip: game.game_zip, zipsize: game.game_size }; if (game.channellist) { for (const channel of game.channellist) { if (channel.channelid == channelid) { if (channel.game_version > 0) { o_game.gameversion = channel.game_version; } if (channel.game_zip) { o_game.gamezip = channel.game_zip; } if (channel.game_size) { o_game.zipsize = channel.game_size; } if (channel.marketlist) { for (const market of channel.marketlist) { if (market.marketid == marketid) { if (market.game_version > 0) { o_game.gameversion = market.game_version; } if (market.game_zip) { o_game.gamezip = market.game_zip; } if (market.game_size) { o_game.zipsize = market.game_size; } break; } } } gamelist.push(o_game); break; } } } } } } break; } } return gamelist; } // 获取代理城市列表 getAgentList(agentid, channelid) { const agentlist = []; if (!this.data || !this.data.agentlist) { return agentlist; } for (const agent of this.data.agentlist) { if (agent.agentid == agentid || agent.relagentid == agentid) { const o_agent = { agentid: agent.agentid, name: agent.agentname, // 注意:这里假设 gamelist 和 channellist 存在且非空,参考原逻辑 channelid: (agent.gamelist && agent.gamelist[0] && agent.gamelist[0].channellist && agent.gamelist[0].channellist[0]) ? agent.gamelist[0].channellist[0].channelid : '' }; agentlist.push(o_agent); } } return agentlist; } // 获取子游戏服务器列表 getGameServerList(agentid) { const iplist = []; const paraname = "game_server_http"; const doPushToIpList = (ip) => { if (ip && !iplist.includes(ip)) { iplist.push(ip); } }; if (!this.data || !this.data.agentlist) { return iplist; } const agent = this.data.agentlist.find(a => a.agentid === agentid); if (!agent) { return iplist; } if (this.data[paraname]) { doPushToIpList(this.data[paraname]); } if (agent[paraname]) { doPushToIpList(agent[paraname]); } if (agent.gamelist) { for (const game of agent.gamelist) { if (game[paraname]) { doPushToIpList(game[paraname]); } } } return iplist; } } module.exports = new RemoteConfig();