- Split monolithic server.js (1111 lines) into route modules - Add .env config (port, session secret, quality, limits) - Add SSRF protection for parser/proxy/redirect endpoints - Add optional password auth middleware - Add structured logger (replaces raw fs.appendFileSync) - Add graceful shutdown with timeout - Add extended /health endpoint (uptime, memory, pid) - Add ecosystem.config.js for PM2 (memory limit, restart policy) - Make compress quality configurable (was hardcoded 60) - Expand SVG AI icons library (7 -> 20 icons) - Add dotenv dependency
69 lines
2.6 KiB
JavaScript
69 lines
2.6 KiB
JavaScript
const express = require('express');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const router = express.Router();
|
|
const LOG_FILE = path.join(__dirname, '..', 'compress.log');
|
|
|
|
// JSON API
|
|
router.get('/api/logs', (req, res) => {
|
|
const lines = parseInt(req.query.lines || '100', 10);
|
|
const filter = (req.query.filter || '').toLowerCase();
|
|
|
|
let logLines = [];
|
|
try {
|
|
const content = fs.readFileSync(LOG_FILE, 'utf8');
|
|
logLines = content.trim().split('\n').filter(Boolean);
|
|
} catch {}
|
|
|
|
if (filter) logLines = logLines.filter(l => l.toLowerCase().includes(filter));
|
|
logLines = logLines.slice(-Math.min(lines, 1000)).reverse();
|
|
res.json({ lines: logLines, total: logLines.length });
|
|
});
|
|
|
|
// Server-rendered logs page
|
|
router.get('/logs', (req, res) => {
|
|
const lines = parseInt(req.query.lines || '100', 10);
|
|
const filter = (req.query.filter || '').toLowerCase();
|
|
|
|
let logLines = [];
|
|
try {
|
|
const content = fs.readFileSync(LOG_FILE, 'utf8');
|
|
logLines = content.trim().split('\n').filter(Boolean);
|
|
} catch {}
|
|
|
|
if (filter) logLines = logLines.filter(l => l.toLowerCase().includes(filter));
|
|
logLines = logLines.slice(-Math.min(lines, 1000)).reverse();
|
|
|
|
const rendered = logLines.map(line => {
|
|
const escaped = line.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
return `<div class="log-line">${escaped}</div>`;
|
|
}).join('\n');
|
|
|
|
res.send(`<!DOCTYPE html>
|
|
<html lang="ru" class="dark"><head>
|
|
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
<title>Logs</title>
|
|
<style>
|
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
body{font-family:'JetBrains Mono',monospace;font-size:13px;background:#060c18;color:#c0c0c0;padding:16px}
|
|
.header{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:16px}
|
|
.header h1{font-size:16px;color:#fff;font-weight:600}
|
|
.header input{background:#091020;border:1px solid #162040;color:#c0c0c0;padding:6px 10px;border-radius:6px;font-size:12px}
|
|
.log-line{padding:6px 10px;border-bottom:1px solid #091020;line-height:1.5;white-space:pre-wrap;word-break:break-all}
|
|
.log-line:hover{background:#091020}
|
|
.empty{text-align:center;padding:40px;color:#555}
|
|
a{color:#0054e6;text-decoration:none}
|
|
</style></head><body>
|
|
<div class="header">
|
|
<a href="/">←</a>
|
|
<h1>Logs (${logLines.length})</h1>
|
|
<form><input name="filter" placeholder="Filter..." value="${filter.replace(/"/g, '"')}">
|
|
<input name="lines" type="number" value="${lines}" style="width:70px"></form>
|
|
</div>
|
|
${logLines.length ? rendered : '<div class="empty">No logs</div>'}
|
|
</body></html>`);
|
|
});
|
|
|
|
module.exports = router;
|