// API Communication Module // Handles all AJAX/Fetch calls and API interactions (function() { 'use strict'; AppModules.register('api'); const API_BASE_URL = ''; // Generic fetch wrapper with error handling and retries function apiRequest(endpoint, options = {}) { const url = endpoint.startsWith('?') ? endpoint : `${API_BASE_URL}${endpoint}`; return fetch(url, { method: options.method || 'GET', headers: { 'Content-Type': 'application/x-www-form-urlencoded', ...options.headers }, body: options.body }) .then(response => { if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } return response.json(); }) .catch(error => { AppLogger.error(`API request to ${endpoint} failed:`, error); throw error; }); } // Stream status checking function checkStreamStatus() { return apiRequest('?api=stream_status') .then(data => { AppLogger.log('Stream status check:', data); return data.online === true; }) .catch(error => { AppLogger.error('Stream status check failed:', error); return false; // Assume offline if check fails }); } // User management function getUserId() { return apiRequest('', { method: 'POST', body: 'action=get_user_id' }) .then(data => { if (data.success) { AppState.userId = data.user_id; AppState.isAdmin = data.is_admin || false; const userIdElement = document.getElementById('userId'); if (userIdElement) { userIdElement.textContent = '#' + AppState.userId; if (AppState.isAdmin) { userIdElement.classList.add('admin'); userIdElement.textContent = '👑 #' + AppState.userId; const adminControls = document.getElementById('adminControls'); if (adminControls) adminControls.style.display = 'flex'; } } return data; } else { throw new Error('Failed to get user ID'); } }); } // Heartbeat functionality function sendHeartbeat() { const nicknameValue = document.getElementById('nickname')?.value || 'Anonymous'; return apiRequest('', { method: 'POST', body: `action=heartbeat&nickname=${encodeURIComponent(nicknameValue)}` }) .then(data => { if (data.success && data.viewer_count !== undefined) { AppState.viewerCount = data.viewer_count; updateViewerCount(data.viewer_count); } }) .catch(error => { AppLogger.error('Heartbeat failed:', error); }); } // Chat message operations function sendMessage(nickname, message) { if (!nickname || !message) { throw new Error('Nickname and message are required'); } const body = `action=send&nickname=${encodeURIComponent(nickname)}&message=${encodeURIComponent(message)}`; return apiRequest('', { method: 'POST', body: body }); } function fetchMessages() { return apiRequest('', { method: 'POST', body: `action=fetch&last_id=${encodeURIComponent(AppState.lastMessageId)}` }) .then(data => { if (data.success) { // Update viewer count if (data.viewer_count !== undefined) { AppState.viewerCount = data.viewer_count; updateViewerCount(data.viewer_count); } return data; } else { throw new Error('Failed to fetch messages'); } }) .catch(error => { AppLogger.error('Fetch messages failed:', error); updateConnectionStatus(false); throw error; }); } // Admin functions function deleteMessage(messageId) { if (!AppState.isAdmin) return Promise.reject(new Error('Admin access required')); return apiRequest('', { method: 'POST', body: `action=delete_message&message_id=${encodeURIComponent(messageId)}` }) .then(data => { if (data.success) { return data; } else { throw new Error('Failed to delete message'); } }); } function banUser(userId) { if (!AppState.isAdmin) return Promise.reject(new Error('Admin access required')); return apiRequest('', { method: 'POST', body: `action=ban_user&user_id=${encodeURIComponent(userId)}` }) .then(data => { if (data.success) { return data; } else { throw new Error('Failed to ban user'); } }); } function clearChat() { if (!AppState.isAdmin) return Promise.reject(new Error('Admin access required')); return apiRequest('', { method: 'POST', body: 'action=clear_chat' }) .then(data => { if (data.success) { return data; } else { throw new Error('Failed to clear chat'); } }); } // UI feedback functions (will be moved to ui-controls later, but needed here for now) function updateViewerCount(count) { const viewerElement = document.getElementById('viewerCount'); if (viewerElement) { viewerElement.textContent = count + (count === 1 ? ' viewer' : ' viewers'); } } function updateConnectionStatus(online) { const statusDot = document.getElementById('statusDot'); const statusText = document.getElementById('statusText'); if (statusDot && statusText) { if (online) { statusDot.classList.remove('offline'); statusText.textContent = 'Connected'; } else { statusDot.classList.add('offline'); statusText.textContent = 'Reconnecting...'; } } } // Public API window.API = { checkStreamStatus: checkStreamStatus, getUserId: getUserId, sendHeartbeat: sendHeartbeat, sendMessage: sendMessage, fetchMessages: fetchMessages, deleteMessage: deleteMessage, banUser: banUser, clearChat: clearChat }; AppLogger.log('API module loaded'); })();