Новый 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);
// --- НАСТРОЙКА EXPRESS ---
const clientOrigin = process.env.CORS_ORIGIN_CLIENT || (process.env.NODE_ENV === 'development' ? '*' : undefined);
console.log(`[BC Server] NODE_ENV: ${process.env.NODE_ENV}`);
console.log(`[BC Server] 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)'}`);
console.log(`[BC.JS CONFIG] Reading environment variables...`);
console.log(`[BC.JS CONFIG] NODE_ENV: ${process.env.NODE_ENV}`);
console.log(`[BC.JS CONFIG] process.env.CORS_ORIGIN_CLIENT: ${process.env.CORS_ORIGIN_CLIENT}`);
if (!clientOrigin && process.env.NODE_ENV !== 'development') {
console.warn("[BC Server Config] CORS_ORIGIN_CLIENT не установлен для не-development сборки. HTTP API могут быть недоступны.");
const clientOrigin = process.env.CORS_ORIGIN_CLIENT || (process.env.NODE_ENV === 'development' ? '*' : undefined);
// Этот лог покажет, какое значение 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({
origin: clientOrigin,
methods: ["GET", "POST"],
credentials: true
credentials: true // Важно, если клиент шлет куки или заголовок Authorization
}));
app.use(express.json());
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));
// --- HTTP МАРШРУТЫ АУТЕНТИФИКАЦИИ ---
app.post('/auth/register', async (req, res) => {
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) {
console.warn('[BC HTTP /auth/register] Bad request: Username or password missing.');
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) => {
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}`);
if (!username || !password) {
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 ---
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);
console.log(`[BC Server] process.env.CORS_ORIGIN_SOCKET: ${process.env.CORS_ORIGIN_SOCKET}`);
console.log(`[BC Server] Calculated Socket.IO CORS Origin (socketCorsOrigin): ${socketCorsOrigin === '*' ? "'*'" : socketCorsOrigin || 'Not explicitly set (will likely fail if not development)'}`);
// Этот лог покажет, какое значение socketCorsOrigin будет использовано для Socket.IO CORS
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') {
console.warn("[BC Server Config] CORS_ORIGIN_SOCKET не установлен для не-development сборки. Socket.IO может быть недоступен.");
if (!socketCorsOrigin && process.env.NODE_ENV !== 'development' && process.env.NODE_ENV !== undefined) { // Добавил проверку на undefined NODE_ENV
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, {
// ВАЖНО: Этот path должен соответствовать тому, как клиент подключается
// и как прокси настроен (особенно stripPrefix для /socket.io).
// Если клиент и прокси работают с /socket.io/ и прокси НЕ отрезает этот префикс
// (stripPrefix: false для /socket.io в config.json), то здесь ДОЛЖЕН быть path.
path: '/socket.io/', // <--- УБЕДИТЕСЬ, ЧТО ЭТА СТРОКА РАСКОММЕНТИРОВАНА И КОРРЕКТНА
path: '/socket.io/', // Убедитесь, что это соответствует настройкам клиента и прокси
cors: {
origin: socketCorsOrigin,
methods: ["GET", "POST"],
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);
@ -105,8 +106,12 @@ const loggedInUsers = {};
// --- MIDDLEWARE АУТЕНТИФИКАЦИИ SOCKET.IO ---
io.use(async (socket, next) => {
const token = socket.handshake.auth.token;
const clientIp = socket.handshake.address; // Может быть IP прокси, если xfwd не настроен на уровне Socket.IO
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}`);
// Пытаемся получить IP клиента, учитывая возможные заголовки от прокси
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) {
try {
@ -125,29 +130,32 @@ io.use(async (socket, next) => {
// --- ОБРАБОТЧИКИ СОБЫТИЙ SOCKET.IO ---
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) {
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;
if (gameManager && typeof gameManager.handleRequestGameState === 'function') {
gameManager.handleRequestGameState(socket, socket.userData.userId);
} 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 {
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', () => {
const username = socket.userData?.username || 'UnknownUser';
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]) {
delete loggedInUsers[socket.id];
}
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', () => {
@ -235,7 +243,7 @@ io.on('connection', (socket) => {
socket.on('disconnect', (reason) => {
const identifier = socket.userData?.userId;
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) {
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';
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);
}
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') {
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') {
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 {
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) => {
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) => {
console.error('[BC Server FATAL] Uncaught Exception:', err);
console.error('[BC Server FATAL UncaughtException] Error:', err);
process.exit(1);
});