require('dotenv').config(); const express = require('express'); const session = require('express-session'); const log = require('./lib/logger'); const authMiddleware = require('./lib/auth'); const app = express(); app.set('trust proxy', 1); // Session app.use(session({ secret: process.env.SESSION_SECRET || 'change-me-in-env', resave: false, saveUninitialized: false, cookie: { maxAge: 30 * 24 * 60 * 60 * 1000 }, })); // Static assets (before auth — always public) app.use(express.static('public')); // Auth routes (before auth middleware — public) app.use('/auth', require('./routes/auth')); // Auth middleware (protects everything below) app.use(authMiddleware); // Health check (extended) const startTime = Date.now(); app.get('/health', (req, res) => { const mem = process.memoryUsage(); res.json({ status: 'ok', uptime: Math.floor((Date.now() - startTime) / 1000), memory: { rss: Math.round(mem.rss / 1024 / 1024) + 'MB', heap: Math.round(mem.heapUsed / 1024 / 1024) + '/' + Math.round(mem.heapTotal / 1024 / 1024) + 'MB', }, node: process.version, pid: process.pid, }); }); // Routes const compressRouter = require('./routes/compress'); app.use('/compress', compressRouter); // Download endpoint const fs = require('fs'); const path = require('path'); app.get('/download/:filename', (req, res) => { const filename = path.basename(req.params.filename); const filePath = path.join(compressRouter.DOWNLOADS_DIR, filename); if (!fs.existsSync(filePath)) return res.status(404).json({ error: 'Файл не найден' }); res.download(filePath, 'compressed.zip'); }); app.use(require('./routes/parser')); app.use('/placeholder', require('./routes/placeholder')); app.use('/placeholder-img', require('./routes/placeholder')); app.use(require('./routes/httpclient')); app.use(require('./routes/redirects')); app.use(require('./routes/svgeditor')); app.use('/video', require('./routes/video')); app.use(require('./routes/logs')); app.use(require('./routes/pages')); // Global error handler app.use((err, req, res, next) => { log.error('Unhandled error', { error: err.message, stack: err.stack }); res.status(500).json({ error: 'Внутренняя ошибка сервера' }); }); // Start server const PORT = parseInt(process.env.PORT) || 3000; const server = app.listen(PORT, () => { log.info(`Server started on http://localhost:${PORT}`); }); // Graceful shutdown function shutdown(signal) { log.info(`${signal} received, shutting down gracefully...`); server.close(() => { log.info('Server closed'); process.exit(0); }); // Force close after 10 seconds setTimeout(() => { log.warn('Forced shutdown after timeout'); process.exit(1); }, 10000); } process.on('SIGTERM', () => shutdown('SIGTERM')); process.on('SIGINT', () => shutdown('SIGINT')); process.on('unhandledRejection', (err) => { log.error('Unhandled rejection', { error: err?.message || String(err) }); }); process.on('uncaughtException', (err) => { log.error('Uncaught exception', { error: err.message, stack: err.stack }); process.exit(1); });