bc/public/js/auth.js

210 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// /public/js/auth.js
// Эта функция будет вызвана из main.js и получит необходимые зависимости
export function initAuth(dependencies) {
const { socket, clientState, ui } = dependencies;
const { loginForm, registerForm, logoutButton } = ui.elements; // Получаем нужные DOM элементы
// URL вашего API сервера. Лучше вынести в конфигурацию или передавать.
// Для примера захардкодим, но в main.js можно будет это улучшить.
const API_BASE_URL = dependencies.API_BASE_URL || 'http://127.0.0.1:3200'; // Убедитесь, что это ваш URL
// Название ключа для хранения JWT в localStorage
const JWT_TOKEN_KEY = 'jwtToken';
async function handleAuthResponse(response, formType) {
const regButton = registerForm ? registerForm.querySelector('button') : null;
const loginButton = loginForm ? loginForm.querySelector('button') : null;
try {
const data = await response.json();
if (response.ok && data.success && data.token) {
// Успешная аутентификация/регистрация
localStorage.setItem(JWT_TOKEN_KEY, data.token); // Сохраняем токен
clientState.isLoggedIn = true;
clientState.loggedInUsername = data.username;
clientState.myUserId = data.userId;
ui.setAuthMessage(''); // Очищаем сообщение об аутентификации
ui.showGameSelectionScreen(data.username); // Показываем экран выбора игры
// Важно: переподключить сокет с новым токеном
if (socket.connected) {
socket.disconnect();
}
// Обновляем auth объект сокета перед подключением
// В main.js при создании сокета, он должен уже брать токен из localStorage
// Но если сокет уже существует, нужно обновить его auth данные
socket.auth = { token: data.token };
socket.connect(); // Это вызовет 'connect' и 'requestGameState' в main.js
} else {
// Ошибка аутентификации/регистрации
clientState.isLoggedIn = false;
clientState.loggedInUsername = '';
clientState.myUserId = null;
localStorage.removeItem(JWT_TOKEN_KEY); // Удаляем старый токен, если был
ui.setAuthMessage(data.message || 'Ошибка сервера.', true);
}
} catch (error) {
// Ошибка парсинга JSON или другая сетевая ошибка
console.error(`[Auth] Error processing ${formType} response:`, error);
clientState.isLoggedIn = false;
clientState.loggedInUsername = '';
clientState.myUserId = null;
localStorage.removeItem(JWT_TOKEN_KEY);
ui.setAuthMessage('Произошла ошибка сети. Попробуйте снова.', true);
} finally {
// Разблокируем кнопки в любом случае
if (regButton) regButton.disabled = false;
if (loginButton) loginButton.disabled = false;
if (logoutButton && clientState.isLoggedIn) logoutButton.disabled = false;
}
}
// --- Обработчики событий DOM ---
if (registerForm) {
registerForm.addEventListener('submit', async (e) => {
e.preventDefault();
const usernameInput = document.getElementById('register-username');
const passwordInput = document.getElementById('register-password');
if (!usernameInput || !passwordInput) return;
const username = usernameInput.value;
const password = passwordInput.value;
const regButton = registerForm.querySelector('button');
const loginButton = loginForm ? loginForm.querySelector('button') : null;
if (regButton) regButton.disabled = true;
if (loginButton) loginButton.disabled = true;
ui.setAuthMessage('Регистрация...');
try {
const response = await fetch(`${API_BASE_URL}/auth/register`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
});
await handleAuthResponse(response, 'register');
if (response.ok && registerForm) registerForm.reset(); // Очищаем форму при успехе
} catch (error) {
console.error('[Auth] Network error during registration:', error);
ui.setAuthMessage('Ошибка сети при регистрации. Пожалуйста, проверьте ваше подключение.', true);
if (regButton) regButton.disabled = false;
if (loginButton) loginButton.disabled = false;
}
});
}
if (loginForm) {
loginForm.addEventListener('submit', async (e) => {
e.preventDefault();
const usernameInput = document.getElementById('login-username');
const passwordInput = document.getElementById('login-password');
if (!usernameInput || !passwordInput) return;
const username = usernameInput.value;
const password = passwordInput.value;
const loginButton = loginForm.querySelector('button');
const regButton = registerForm ? registerForm.querySelector('button') : null;
if (loginButton) loginButton.disabled = true;
if (regButton) regButton.disabled = true;
ui.setAuthMessage('Вход...');
try {
const response = await fetch(`${API_BASE_URL}/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
});
await handleAuthResponse(response, 'login');
} catch (error) {
console.error('[Auth] Network error during login:', error);
ui.setAuthMessage('Ошибка сети при входе. Пожалуйста, проверьте ваше подключение.', true);
if (loginButton) loginButton.disabled = false;
if (regButton) regButton.disabled = false;
}
});
}
if (logoutButton) {
logoutButton.addEventListener('click', () => {
logoutButton.disabled = true;
// --- НАЧАЛО ИЗМЕНЕНИЯ ---
// Если игрок в активной PvP игре, отправляем сигнал о сдаче
if (clientState.isLoggedIn &&
clientState.isInGame &&
clientState.currentGameId &&
clientState.currentGameState && // Убедимся, что gameState существует
clientState.currentGameState.gameMode === 'pvp' && // Проверяем режим игры
!clientState.currentGameState.isGameOver) { // Только если игра еще не закончена
console.log('[Auth] Player is in an active PvP game. Emitting playerSurrender.');
socket.emit('playerSurrender');
// Не ждем ответа от сервера здесь, так как logout - это безусловное действие на клиенте.
// Сервер обработает 'playerSurrender' и соответствующим образом завершит игру.
}
// --- КОНЕЦ ИЗМЕНЕНИЯ ---
// Серверный эндпоинт для логаута не обязателен для JWT,
// если нет необходимости аннулировать токен на сервере (что сложно с JWT).
// Основное действие - удаление токена на клиенте.
// socket.emit('logout'); // Можно оставить, если на сервере есть логика для этого (например, GameManager.handleDisconnect)
localStorage.removeItem(JWT_TOKEN_KEY); // Удаляем токен
clientState.isLoggedIn = false;
clientState.loggedInUsername = '';
clientState.myUserId = null;
// isInGame и другие игровые переменные сбросятся в ui.showAuthScreen()
// ui.disableGameControls() также будет вызван опосредованно
ui.showAuthScreen(); // Показываем экран логина
ui.setGameStatusMessage("Вы вышли из системы."); // Можно заменить на ui.setAuthMessage, если хотим видеть сообщение на экране логина
// Переподключаем сокет без токена
if (socket.connected) {
socket.disconnect();
}
socket.auth = { token: null }; // Очищаем токен в auth объекте сокета
socket.connect(); // Сокет подключится как неаутентифицированный
// Кнопка logout будет активирована, когда пользователь снова войдет
// или если она видна только залогиненным пользователям, то исчезнет.
// (В showAuthScreen logoutButton.disabled устанавливается в true)
});
}
// --- Обработчики событий Socket.IO ---
// Старые 'registerResponse' и 'loginResponse' больше не нужны,
// так как эти ответы приходят через HTTP.
// Можно добавить обработчик для принудительного разлогинивания от сервера, если такой будет
// socket.on('forceLogout', (data) => {
// console.log('[Auth] Forced logout by server:', data.message);
// localStorage.removeItem(JWT_TOKEN_KEY);
// clientState.isLoggedIn = false;
// clientState.loggedInUsername = '';
// clientState.myUserId = null;
// ui.showAuthScreen();
// ui.setAuthMessage(data.message || "Вы были разлогинены сервером.");
// if (socket.connected) socket.disconnect();
// socket.auth = { token: null };
// socket.connect();
// });
// При загрузке модуля auth.js, проверяем, нет ли уже токена в localStorage
// Эта логика лучше всего будет работать в main.js при инициализации сокета,
// но здесь можно было бы сделать предварительную проверку и обновление clientState,
// если бы это было необходимо до создания сокета.
// Однако, поскольку сокет создается в main.js и сразу использует токен из localStorage,
// отдельная логика здесь не так критична.
}