const express = require('express'); const mongoose = require('mongoose'); const cors = require('cors'); const dotenv = require('dotenv'); const path = require('path'); const http = require('http'); const { generalLimiter } = require('./middleware/rateLimiter'); const { initRedis } = require('./utils/redis'); const { initWebSocket } = require('./websocket'); const config = require('./config'); dotenv.config(); const app = express(); const server = http.createServer(app); // CORS настройки const corsOptions = { origin: config.corsOrigin === '*' ? '*' : config.corsOrigin.split(','), credentials: true, optionsSuccessStatus: 200 }; // Middleware app.use(cors(corsOptions)); app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.use('/uploads', express.static(path.join(__dirname, config.uploadsDir))); // Доверять proxy для правильного IP (для rate limiting за nginx/cloudflare) if (config.isProduction()) { app.set('trust proxy', 1); } // Rate limiting app.use('/api', generalLimiter); // Health check endpoint app.get('/health', (req, res) => { res.json({ status: 'ok', environment: config.nodeEnv, timestamp: new Date().toISOString() }); }); // MongoDB подключение mongoose.connect(config.mongoUri, { useNewUrlParser: true, useUnifiedTopology: true }) .then(() => { console.log(`✅ MongoDB подключена: ${config.mongoUri.replace(/\/\/.*@/, '//***@')}`); // Инициализировать Redis (опционально) if (config.redisUrl) { initRedis().catch(err => console.log('⚠️ Redis недоступен, работаем без кэша')); } else { console.log('ℹ️ Redis не настроен, кэширование отключено'); } }) .catch(err => console.error('❌ Ошибка MongoDB:', err)); // Routes app.use('/api/auth', require('./routes/auth')); app.use('/api/posts', require('./routes/posts')); app.use('/api/users', require('./routes/users')); app.use('/api/notifications', require('./routes/notifications')); app.use('/api/search', require('./routes/search')); app.use('/api/search/posts', require('./routes/postSearch')); app.use('/api/moderation', require('./routes/moderation')); app.use('/api/statistics', require('./routes/statistics')); app.use('/api/bot', require('./routes/bot')); // Базовый роут app.get('/', (req, res) => { res.json({ message: 'NakamaSpace API работает' }); }); // Инициализировать WebSocket initWebSocket(server); // Graceful shutdown process.on('SIGTERM', () => { console.log('SIGTERM получен, закрываем сервер...'); server.close(() => { console.log('Сервер закрыт'); mongoose.connection.close(false, () => { console.log('MongoDB соединение закрыто'); process.exit(0); }); }); }); server.listen(config.port, '0.0.0.0', () => { console.log(`🚀 Сервер запущен`); console.log(` Порт: ${config.port}`); console.log(` Окружение: ${config.nodeEnv}`); console.log(` API: http://0.0.0.0:${config.port}/api`); if (config.isDevelopment()) { console.log(` Frontend: ${config.frontendUrl}`); } });