nakama/moderation/backend/server.js

185 lines
5.9 KiB
JavaScript
Raw Normal View History

2025-12-08 23:42:32 +00:00
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');
2025-12-09 01:03:25 +00:00
const { initMinioClient, checkConnection: checkMinioConnection } = require('../../backend/utils/minio');
const { printMinioConfig } = require('../../backend/utils/minioDebug');
const { log, logSuccess, logError } = require('../../backend/middleware/logger');
2025-12-08 23:42:32 +00:00
// 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);
2025-12-09 00:29:13 +00:00
// Trust proxy для правильного IP и HTTPS
// В production доверяем прокси (nginx), чтобы правильно определять HTTPS
app.set('trust proxy', config.isProduction() ? 1 : false);
2025-12-08 23:42:32 +00:00
// 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 переподключена');
});
2025-12-09 01:03:25 +00:00
// Инициализировать 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 отключен, используется локальное хранилище');
}
2025-12-08 23:42:32 +00:00
})
.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');
});