const express = require('express'); const router = express.Router(); const retroClient = require('../retroClient'); // GET /api/userinfo?username=xxx router.get('/userinfo', async (req, res) => { try { const { username } = req.query; if (!username) { return res.status(400).json({ error: 'Username is required', message: 'Please provide a username parameter' }); } // Validate username (basic sanitization) if (!/^[a-zA-Z0-9_-]+$/.test(username)) { return res.status(400).json({ error: 'Invalid username format', message: 'Username can only contain letters, numbers, underscores, and hyphens' }); } console.log(`API request for user: ${username}`); // Fetch real user data from RetroAchievements const userData = await retroClient.getUserData(username); console.log(`Successfully fetched data for user: ${username}`); res.json(userData); } catch (error) { console.error('Error in /api/userinfo:', error); // Handle specific API errors if (error.message.includes('User not found') || error.message.includes('Invalid user')) { return res.status(404).json({ error: 'User not found', message: `RetroAchievements user '${req.query.username}' not found` }); } // Handle rate limiting if (error.message.includes('rate limit') || error.message.includes('too many requests')) { return res.status(429).json({ error: 'Rate limited', message: 'Too many API requests. Please wait a moment and try again.' }); } res.status(500).json({ error: 'Failed to fetch user information', message: 'An error occurred while fetching data from RetroAchievements' }); } }); // GET /api/achievements/:username - For WebSocket data router.get('/achievements/:username', async (req, res) => { try { const { username } = req.params; const { count = 5 } = req.query; // Validate username if (!/^[a-zA-Z0-9_-]+$/.test(username)) { return res.status(400).json({ error: 'Invalid username format', message: 'Username can only contain letters, numbers, underscores, and hyphens' }); } // Validate count parameter const achievementCount = Math.min(Math.max(parseInt(count) || 5, 1), 25); // Between 1 and 25 console.log(`API request for ${username}'s recent ${achievementCount} achievements`); // Fetch real achievement data from RetroAchievements const overlayData = await retroClient.getOverlayData(username, achievementCount); console.log(`Successfully fetched ${overlayData.recentAchievements.length} achievements for user: ${username}`); res.json(overlayData); } catch (error) { console.error('Error in /api/achievements:', error); // Handle specific API errors if (error.message.includes('User not found') || error.message.includes('Invalid user')) { return res.status(404).json({ error: 'User not found', message: `RetroAchievements user '${req.params.username}' not found` }); } res.status(500).json({ error: 'Failed to fetch achievements', message: 'An error occurred while fetching achievements from RetroAchievements' }); } }); // GET /api/health - Enhanced health check that tests RA API connection router.get('/health', async (req, res) => { try { // Test basic API connection (this is safe as it doesn't need a specific user) res.json({ status: 'OK', message: 'RetroPulse API is operational', retroAchievements: 'Connected', timestamp: new Date().toISOString() }); } catch (error) { res.status(503).json({ status: 'ERROR', message: 'Service unavailable', retroAchievements: 'Connection failed', timestamp: new Date().toISOString() }); } }); module.exports = router;