nakama/moderation/backend/server.js

185 lines
5.9 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.

const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
const cookieParser = require('cookie-parser');
const dotenv = require('dotenv');
const path = require('path');
const http = require('http');
// Загрузить переменные окружения из корня проекта
const rootEnvPath = path.resolve(__dirname, '../../.env');
dotenv.config({ path: rootEnvPath });
const config = require('../../backend/config');
const { initWebSocket } = require('../../backend/websocket');
const { initMinioClient, checkConnection: checkMinioConnection } = require('../../backend/utils/minio');
const { printMinioConfig } = require('../../backend/utils/minioDebug');
const { log, logSuccess, logError } = require('../../backend/middleware/logger');
// Security middleware
const {
helmetConfig,
sanitizeMongo,
xssProtection,
hppProtection,
ddosProtection
} = require('../../backend/middleware/security');
const { sanitizeInput } = require('../../backend/middleware/validator');
const { requestLogger } = require('../../backend/middleware/logger');
const { errorHandler, notFoundHandler } = require('../../backend/middleware/errorHandler');
const { generalLimiter } = require('../../backend/middleware/rateLimiter');
const app = express();
const server = http.createServer(app);
// Trust proxy для правильного IP и HTTPS
// В production доверяем прокси (nginx), чтобы правильно определять HTTPS
app.set('trust proxy', config.isProduction() ? 1 : false);
// Security headers
app.use(helmetConfig);
// CORS настройки для модераторского сайта
const corsOptions = {
origin: process.env.MODERATION_CORS_ORIGIN || config.frontendUrl || '*',
credentials: true,
optionsSuccessStatus: 200,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'x-telegram-init-data'],
maxAge: 86400
};
app.use(cors(corsOptions));
// Cookie parser для JWT токенов в cookies
app.use(cookieParser());
// Body parsing
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
// Security middleware
app.use(sanitizeMongo);
app.use(xssProtection);
app.use(hppProtection);
// Input sanitization
app.use(sanitizeInput);
// Request logging
app.use(requestLogger);
// DDoS protection
app.use(ddosProtection);
// Rate limiting
app.use('/api', generalLimiter);
// Health check
app.get('/health', (req, res) => {
res.json({
status: 'ok',
service: 'moderation',
timestamp: new Date().toISOString()
});
});
// MongoDB подключение (используем ту же БД)
mongoose.connect(config.mongoUri)
.then(async () => {
console.log('✅ MongoDB подключена для модерации');
mongoose.connection.on('error', (err) => {
console.error('❌ MongoDB connection error:', err);
});
mongoose.connection.on('disconnected', () => {
console.warn('⚠️ MongoDB отключена');
});
mongoose.connection.on('reconnected', () => {
console.log('✅ MongoDB переподключена');
});
// Инициализировать MinIO (опционально)
if (config.minio.enabled) {
try {
log('info', 'Инициализация MinIO для модерации...');
// Вывести конфигурацию и проверки
printMinioConfig();
initMinioClient();
const minioOk = await checkMinioConnection();
if (minioOk) {
logSuccess('MinIO успешно подключен для модерации', {
endpoint: `${config.minio.endpoint}:${config.minio.port}`,
bucket: config.minio.bucket,
ssl: config.minio.useSSL
});
} else {
log('warn', 'MinIO недоступен, используется локальное хранилище');
}
} catch (err) {
logError('MinIO initialization failed for moderation', err, {
endpoint: `${config.minio.endpoint}:${config.minio.port}`
});
log('warn', 'Используется локальное хранилище');
}
} else {
log('info', 'MinIO отключен, используется локальное хранилище');
}
})
.catch(err => {
console.error('❌ Не удалось подключиться к MongoDB:', err);
process.exit(1);
});
// Routes - используем те же роуты из основного бэкенда
app.use('/api/mod-app', require('../../backend/routes/modApp'));
app.use('/api/moderation-auth', require('../../backend/routes/moderationAuth'));
// Базовый роут
app.get('/', (req, res) => {
res.json({ message: 'Nakama Moderation API' });
});
// 404 handler
app.use(notFoundHandler);
// Error handler
app.use(errorHandler);
// Инициализировать WebSocket
initWebSocket(server);
// Graceful shutdown
process.on('SIGTERM', () => {
console.log('SIGTERM получен, закрываем сервер модерации...');
server.close(() => {
mongoose.connection.close(false, () => {
process.exit(0);
});
});
});
process.on('SIGINT', () => {
console.log('SIGINT получен, закрываем сервер модерации...');
server.close(() => {
mongoose.connection.close(false, () => {
process.exit(0);
});
});
});
const moderationPort = process.env.MODERATION_PORT || 3001;
server.listen(moderationPort, '0.0.0.0', () => {
console.log('\n' + '='.repeat(60));
console.log('✅ Сервер модерации запущен');
console.log(` 🌐 API: http://0.0.0.0:${moderationPort}/api`);
console.log(` 📦 MongoDB: ${config.mongoUri.includes('localhost') ? 'Local' : 'Remote'}`);
console.log('='.repeat(60) + '\n');
});