const logger = require('../utils/logger'); /** * API Mod Service - Handles mod management through API communication with GameServer * This service acts as a client to the GameServer's mod functionality */ class ApiModService { constructor() { // Use service discovery - try multiple common GameServer locations this.gameServerUrls = [ process.env.GAME_SERVER_URL, 'http://localhost:3002', 'http://127.0.0.1:3002', 'http://game-server:3002' // Docker service name ].filter(url => url); // Remove null/undefined values this.currentUrlIndex = 0; } async getGameServerUrl() { // Try each URL until we find a working one for (let i = 0; i < this.gameServerUrls.length; i++) { const url = this.gameServerUrls[i]; try { const response = await fetch(`${url}/health`, { timeout: 5000 // 5 second timeout }); if (response.ok) { this.currentUrlIndex = i; return url; } } catch (error) { logger.debug(`[API MOD SERVICE] GameServer at ${url} not available:`, error.message); } } throw new Error('No GameServer instances available'); } async makeRequest(endpoint, options = {}) { const url = await this.getGameServerUrl(); const fullUrl = `${url}${endpoint}`; const defaultOptions = { timeout: 10000, // 10 second timeout headers: { 'Content-Type': 'application/json', 'User-Agent': 'API-ModService/1.0' } }; const finalOptions = { ...defaultOptions, ...options }; try { const response = await fetch(fullUrl, finalOptions); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } return await response.json(); } catch (error) { logger.error(`[API MOD SERVICE] Request to ${fullUrl} failed:`, error); // If request failed, try next GameServer URL this.currentUrlIndex = (this.currentUrlIndex + 1) % this.gameServerUrls.length; throw error; } } async getMods(enabledOnly = false) { try { const endpoint = `/api/mods${enabledOnly ? '?enabledOnly=true' : ''}`; return await this.makeRequest(endpoint); } catch (error) { logger.error('[API MOD SERVICE] Error getting mods:', error); throw error; } } async getMod(id) { try { return await this.makeRequest(`/api/mods/${id}`); } catch (error) { logger.error('[API MOD SERVICE] Error getting mod:', error); throw error; } } async enableMod(id) { try { return await this.makeRequest(`/api/mods/${id}/enable`, { method: 'POST' }); } catch (error) { logger.error('[API MOD SERVICE] Error enabling mod:', error); throw error; } } async disableMod(id) { try { return await this.makeRequest(`/api/mods/${id}/disable`, { method: 'POST' }); } catch (error) { logger.error('[API MOD SERVICE] Error disabling mod:', error); throw error; } } async getModAssets(assetType) { try { return await this.makeRequest(`/api/mods/assets/${assetType}`); } catch (error) { logger.error('[API MOD SERVICE] Error getting mod assets:', error); throw error; } } async getModAsset(assetType, assetId) { try { return await this.makeRequest(`/api/mods/assets/${assetType}/${assetId}`); } catch (error) { logger.error('[API MOD SERVICE] Error getting mod asset:', error); throw error; } } async getLoadOrder() { try { return await this.makeRequest('/api/mods/load-order'); } catch (error) { logger.error('[API MOD SERVICE] Error getting load order:', error); throw error; } } async setLoadOrder(modIds) { try { return await this.makeRequest('/api/mods/load-order', { method: 'POST', body: JSON.stringify({ modIds }) }); } catch (error) { logger.error('[API MOD SERVICE] Error setting load order:', error); throw error; } } async getServerPreferences() { try { return await this.makeRequest('/api/mods/preferences/server'); } catch (error) { logger.error('[API MOD SERVICE] Error getting server preferences:', error); throw error; } } async setServerPreference(key, value) { try { return await this.makeRequest('/api/mods/preferences/server', { method: 'POST', body: JSON.stringify({ key, value }) }); } catch (error) { logger.error('[API MOD SERVICE] Error setting server preference:', error); throw error; } } async reloadMods() { try { return await this.makeRequest('/api/mods/reload', { method: 'POST' }); } catch (error) { logger.error('[API MOD SERVICE] Error reloading mods:', error); throw error; } } } module.exports = new ApiModService();