Новый bc.js

This commit is contained in:
PsiMagistr 2025-05-25 14:16:48 +03:00
parent 5a6472ffdb
commit e1cb3f33b5

View File

@ -18,31 +18,35 @@ const app = express();
const server = http.createServer(app); const server = http.createServer(app);
// --- НАСТРОЙКА EXPRESS --- // --- НАСТРОЙКА EXPRESS ---
const clientOrigin = process.env.CORS_ORIGIN_CLIENT || (process.env.NODE_ENV === 'development' ? '*' : undefined); console.log(`[BC.JS CONFIG] Reading environment variables...`);
console.log(`[BC Server] NODE_ENV: ${process.env.NODE_ENV}`); console.log(`[BC.JS CONFIG] NODE_ENV: ${process.env.NODE_ENV}`);
console.log(`[BC Server] process.env.CORS_ORIGIN_CLIENT: ${process.env.CORS_ORIGIN_CLIENT}`); console.log(`[BC.JS CONFIG] process.env.CORS_ORIGIN_CLIENT: ${process.env.CORS_ORIGIN_CLIENT}`);
console.log(`[BC Server] Calculated HTTP CORS Origin (clientOrigin): ${clientOrigin === '*' ? "'*'" : clientOrigin || 'Not explicitly set (will likely fail if not development)'}`);
if (!clientOrigin && process.env.NODE_ENV !== 'development') { const clientOrigin = process.env.CORS_ORIGIN_CLIENT || (process.env.NODE_ENV === 'development' ? '*' : undefined);
console.warn("[BC Server Config] CORS_ORIGIN_CLIENT не установлен для не-development сборки. HTTP API могут быть недоступны."); // Этот лог покажет, какое значение clientOrigin будет использовано для HTTP CORS
console.log(`[BC.JS CONFIG] Effective clientOrigin for HTTP CORS: ${clientOrigin === '*' ? "'*'" : clientOrigin || 'NOT SET (CORS will likely fail if not development)'}`);
if (!clientOrigin && process.env.NODE_ENV !== 'development' && process.env.NODE_ENV !== undefined) { // Добавил проверку на undefined NODE_ENV
console.warn("[BC.JS CONFIG WARNING] CORS_ORIGIN_CLIENT is not set for a non-development and non-undefined NODE_ENV. HTTP API requests from browsers might be blocked by CORS.");
} }
app.use(cors({ app.use(cors({
origin: clientOrigin, origin: clientOrigin,
methods: ["GET", "POST"], methods: ["GET", "POST"],
credentials: true credentials: true // Важно, если клиент шлет куки или заголовок Authorization
})); }));
app.use(express.json()); app.use(express.json());
const publicPath = path.join(__dirname, '..', 'public'); const publicPath = path.join(__dirname, '..', 'public');
console.log(`[BC Server] Serving static files from: ${publicPath}`); console.log(`[BC.JS CONFIG] Serving static files from: ${publicPath}`);
app.use(express.static(publicPath)); app.use(express.static(publicPath));
// --- HTTP МАРШРУТЫ АУТЕНТИФИКАЦИИ --- // --- HTTP МАРШРУТЫ АУТЕНТИФИКАЦИИ ---
app.post('/auth/register', async (req, res) => { app.post('/auth/register', async (req, res) => {
const { username, password } = req.body; const { username, password } = req.body;
console.log(`[BC HTTP /auth/register] Attempt for username: "${username}" from IP: ${req.ip}`); // Логируем входящий Origin для этого запроса
console.log(`[BC HTTP /auth/register] Attempt for username: "${username}" from IP: ${req.ip}. Origin header: ${req.headers.origin}`);
if (!username || !password) { if (!username || !password) {
console.warn('[BC HTTP /auth/register] Bad request: Username or password missing.'); console.warn('[BC HTTP /auth/register] Bad request: Username or password missing.');
return res.status(400).json({ success: false, message: 'Имя пользователя и пароль обязательны.' }); return res.status(400).json({ success: false, message: 'Имя пользователя и пароль обязательны.' });
@ -59,6 +63,7 @@ app.post('/auth/register', async (req, res) => {
app.post('/auth/login', async (req, res) => { app.post('/auth/login', async (req, res) => {
const { username, password } = req.body; const { username, password } = req.body;
// Логируем входящий Origin для этого запроса
console.log(`[BC HTTP /auth/login] Attempt for username: "${username}" from IP: ${req.ip}. Origin header: ${req.headers.origin}`); console.log(`[BC HTTP /auth/login] Attempt for username: "${username}" from IP: ${req.ip}. Origin header: ${req.headers.origin}`);
if (!username || !password) { if (!username || !password) {
console.warn('[BC HTTP /auth/login] Bad request: Username or password missing.'); console.warn('[BC HTTP /auth/login] Bad request: Username or password missing.');
@ -75,28 +80,24 @@ app.post('/auth/login', async (req, res) => {
}); });
// --- НАСТРОЙКА SOCKET.IO --- // --- НАСТРОЙКА SOCKET.IO ---
console.log(`[BC.JS CONFIG] process.env.CORS_ORIGIN_SOCKET: ${process.env.CORS_ORIGIN_SOCKET}`);
const socketCorsOrigin = process.env.CORS_ORIGIN_SOCKET || (process.env.NODE_ENV === 'development' ? '*' : undefined); const socketCorsOrigin = process.env.CORS_ORIGIN_SOCKET || (process.env.NODE_ENV === 'development' ? '*' : undefined);
console.log(`[BC Server] process.env.CORS_ORIGIN_SOCKET: ${process.env.CORS_ORIGIN_SOCKET}`); // Этот лог покажет, какое значение socketCorsOrigin будет использовано для Socket.IO CORS
console.log(`[BC Server] Calculated Socket.IO CORS Origin (socketCorsOrigin): ${socketCorsOrigin === '*' ? "'*'" : socketCorsOrigin || 'Not explicitly set (will likely fail if not development)'}`); console.log(`[BC.JS CONFIG] Effective socketCorsOrigin for Socket.IO CORS: ${socketCorsOrigin === '*' ? "'*'" : socketCorsOrigin || 'NOT SET (Socket.IO CORS will likely fail if not development)'}`);
if (!socketCorsOrigin && process.env.NODE_ENV !== 'development') { if (!socketCorsOrigin && process.env.NODE_ENV !== 'development' && process.env.NODE_ENV !== undefined) { // Добавил проверку на undefined NODE_ENV
console.warn("[BC Server Config] CORS_ORIGIN_SOCKET не установлен для не-development сборки. Socket.IO может быть недоступен."); console.warn("[BC.JS CONFIG WARNING] CORS_ORIGIN_SOCKET is not set for a non-development and non-undefined NODE_ENV. Socket.IO connections from browsers might be blocked by CORS.");
} }
const io = new Server(server, { const io = new Server(server, {
// ВАЖНО: Этот path должен соответствовать тому, как клиент подключается path: '/socket.io/', // Убедитесь, что это соответствует настройкам клиента и прокси
// и как прокси настроен (особенно stripPrefix для /socket.io).
// Если клиент и прокси работают с /socket.io/ и прокси НЕ отрезает этот префикс
// (stripPrefix: false для /socket.io в config.json), то здесь ДОЛЖЕН быть path.
path: '/socket.io/', // <--- УБЕДИТЕСЬ, ЧТО ЭТА СТРОКА РАСКОММЕНТИРОВАНА И КОРРЕКТНА
cors: { cors: {
origin: socketCorsOrigin, origin: socketCorsOrigin,
methods: ["GET", "POST"], methods: ["GET", "POST"],
credentials: true credentials: true
}, },
// transports: ['websocket', 'polling'], // Можно оставить по умолчанию или указать явно
}); });
console.log(`[BC Server] Socket.IO server configured with path: ${io.path()} and CORS origin: ${socketCorsOrigin === '*' ? "'*'" : socketCorsOrigin || 'Not set'}`); console.log(`[BC.JS CONFIG] Socket.IO server configured with path: ${io.path()} and effective CORS origin: ${io.opts.cors.origin === '*' ? "'*'" : io.opts.cors.origin || 'NOT SET'}`);
const gameManager = new GameManager(io); const gameManager = new GameManager(io);
@ -105,8 +106,12 @@ const loggedInUsers = {};
// --- MIDDLEWARE АУТЕНТИФИКАЦИИ SOCKET.IO --- // --- MIDDLEWARE АУТЕНТИФИКАЦИИ SOCKET.IO ---
io.use(async (socket, next) => { io.use(async (socket, next) => {
const token = socket.handshake.auth.token; const token = socket.handshake.auth.token;
const clientIp = socket.handshake.address; // Может быть IP прокси, если xfwd не настроен на уровне Socket.IO // Пытаемся получить IP клиента, учитывая возможные заголовки от прокси
console.log(`[BC Socket.IO Middleware] Auth attempt for socket ${socket.id} from IP ${clientIp}. Token ${token ? 'present' : 'absent'}. Origin: ${socket.handshake.headers.origin}. Path: ${socket.nsp.name}`); const clientIp = socket.handshake.headers['x-forwarded-for']?.split(',')[0].trim() || socket.handshake.address;
const originHeader = socket.handshake.headers.origin;
const socketPath = socket.nsp.name;
console.log(`[BC Socket.IO Middleware] Auth attempt for socket ${socket.id} from IP ${clientIp}. Token ${token ? 'present' : 'absent'}. Origin: ${originHeader}. Path: ${socketPath}`);
if (token) { if (token) {
try { try {
@ -125,29 +130,32 @@ io.use(async (socket, next) => {
// --- ОБРАБОТЧИКИ СОБЫТИЙ SOCKET.IO --- // --- ОБРАБОТЧИКИ СОБЫТИЙ SOCKET.IO ---
io.on('connection', (socket) => { io.on('connection', (socket) => {
const clientIp = socket.handshake.headers['x-forwarded-for']?.split(',')[0].trim() || socket.handshake.address;
const originHeader = socket.handshake.headers.origin;
const socketPath = socket.nsp.name;
if (socket.userData && socket.userData.userId) { if (socket.userData && socket.userData.userId) {
console.log(`[BC Socket.IO] Authenticated user ${socket.userData.username} (ID: ${socket.userData.userId}) connected with socket: ${socket.id} to path ${socket.nsp.name}`); console.log(`[BC Socket.IO Connection] Authenticated user ${socket.userData.username} (ID: ${socket.userData.userId}) connected. Socket: ${socket.id}, IP: ${clientIp}, Origin: ${originHeader}, Path: ${socketPath}`);
loggedInUsers[socket.id] = socket.userData; loggedInUsers[socket.id] = socket.userData;
if (gameManager && typeof gameManager.handleRequestGameState === 'function') { if (gameManager && typeof gameManager.handleRequestGameState === 'function') {
gameManager.handleRequestGameState(socket, socket.userData.userId); gameManager.handleRequestGameState(socket, socket.userData.userId);
} else { } else {
console.error("[BC Socket.IO] CRITICAL: gameManager or handleRequestGameState not available on connect for authenticated user!"); console.error("[BC Socket.IO Connection] CRITICAL: gameManager or handleRequestGameState not available for authenticated user!");
} }
} else { } else {
console.log(`[BC Socket.IO] Unauthenticated user connected with socket: ${socket.id} to path ${socket.nsp.name}. No game state will be restored.`); console.log(`[BC Socket.IO Connection] Unauthenticated user connected. Socket: ${socket.id}, IP: ${clientIp}, Origin: ${originHeader}, Path: ${socketPath}. No game state will be restored.`);
} }
// ... (остальные обработчики событий: logout, playerSurrender, createGame, и т.д. остаются как в вашей версии с логами) ... // ... (остальные обработчики событий: logout, playerSurrender, createGame, и т.д. как в предыдущей версии) ...
// Копирую их из вашего предыдущего варианта для полноты:
socket.on('logout', () => { socket.on('logout', () => {
const username = socket.userData?.username || 'UnknownUser'; const username = socket.userData?.username || 'UnknownUser';
const userId = socket.userData?.userId; const userId = socket.userData?.userId;
console.log(`[BC Socket.IO] 'logout' event from user ${username} (ID: ${userId}, Socket: ${socket.id})`); console.log(`[BC Socket.IO 'logout'] Event from user ${username} (ID: ${userId}, Socket: ${socket.id})`);
if (loggedInUsers[socket.id]) { if (loggedInUsers[socket.id]) {
delete loggedInUsers[socket.id]; delete loggedInUsers[socket.id];
} }
socket.userData = null; socket.userData = null;
console.log(`[BC Socket.IO] User ${username} (Socket: ${socket.id}) session data cleared on server due to 'logout' event.`); console.log(`[BC Socket.IO 'logout'] User ${username} (Socket: ${socket.id}) session data cleared.`);
}); });
socket.on('playerSurrender', () => { socket.on('playerSurrender', () => {
@ -235,7 +243,7 @@ io.on('connection', (socket) => {
socket.on('disconnect', (reason) => { socket.on('disconnect', (reason) => {
const identifier = socket.userData?.userId; const identifier = socket.userData?.userId;
const username = socket.userData?.username || 'UnauthenticatedUser'; const username = socket.userData?.username || 'UnauthenticatedUser';
console.log(`[BC Socket.IO] User ${username} (ID: ${identifier || 'N/A'}, Socket: ${socket.id}) disconnected. Reason: ${reason}.`); console.log(`[BC Socket.IO Disconnect] User ${username} (ID: ${identifier || 'N/A'}, Socket: ${socket.id}) disconnected. Reason: ${reason}.`);
if (identifier) { if (identifier) {
gameManager.handleDisconnect(socket.id, identifier); gameManager.handleDisconnect(socket.id, identifier);
} }
@ -250,27 +258,30 @@ const PORT = parseInt(process.env.BC_APP_PORT || '3200', 10);
const HOSTNAME = process.env.BC_APP_HOSTNAME || '127.0.0.1'; const HOSTNAME = process.env.BC_APP_HOSTNAME || '127.0.0.1';
if (isNaN(PORT)) { if (isNaN(PORT)) {
console.error(`[BC Server FATAL] Некорректное значение для BC_APP_PORT: "${process.env.BC_APP_PORT}". Ожидается число.`); console.error(`[BC Server FATAL] Invalid BC_APP_PORT: "${process.env.BC_APP_PORT}". Expected a number.`);
process.exit(1); process.exit(1);
} }
server.listen(PORT, HOSTNAME, () => { server.listen(PORT, HOSTNAME, () => {
console.log(`[BC Server] Battle Club HTTP Application Server running at http://${HOSTNAME}:${PORT}`); console.log(`[BC Server Startup] Battle Club HTTP Application Server running at http://${HOSTNAME}:${PORT}`);
if (HOSTNAME === '127.0.0.1') { if (HOSTNAME === '127.0.0.1') {
console.log(`[BC Server] Server is listening on localhost only. This is suitable if a reverse proxy handles external traffic.`); console.log(`[BC Server Startup] Server is listening on localhost only.`);
} else if (HOSTNAME === '0.0.0.0') { } else if (HOSTNAME === '0.0.0.0') {
console.log(`[BC Server] Server is listening on all available network interfaces.`); console.log(`[BC Server Startup] Server is listening on all available network interfaces.`);
} else { } else {
console.log(`[BC Server] Server is listening on a specific interface: ${HOSTNAME}.`); console.log(`[BC Server Startup] Server is listening on a specific interface: ${HOSTNAME}.`);
} }
console.log(`[BC Server] Static files served from: ${publicPath}`); console.log(`[BC Server Startup] Static files served from: ${publicPath}`);
console.log(`[BC.JS Startup] Socket.IO server effective path: ${io.path()}`);
console.log(`[BC.JS Startup] HTTP API effective CORS origin: ${app.get('env') === 'development' && !process.env.CORS_ORIGIN_CLIENT ? "'*'" : clientOrigin || 'NOT SET'}`); // Это немного упрощенный вывод, точнее в логах CONFIG
console.log(`[BC.JS Startup] Socket.IO effective CORS origin: ${io.opts.cors.origin === '*' ? "'*'" : io.opts.cors.origin || 'NOT SET'}`);
}); });
process.on('unhandledRejection', (reason, promise) => { process.on('unhandledRejection', (reason, promise) => {
console.error('[BC Server FATAL] Unhandled Rejection at:', promise, 'reason:', reason); console.error('[BC Server FATAL UnhandledRejection] Reason:', reason, 'Promise:', promise);
}); });
process.on('uncaughtException', (err) => { process.on('uncaughtException', (err) => {
console.error('[BC Server FATAL] Uncaught Exception:', err); console.error('[BC Server FATAL UncaughtException] Error:', err);
process.exit(1); process.exit(1);
}); });