wa-dev-tools/routes/logs.js
treamz 5b528d243a Refactor: modular architecture, security, config
- 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
2026-03-21 22:18:54 +03:00

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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
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="/">&larr;</a>
<h1>Logs (${logLines.length})</h1>
<form><input name="filter" placeholder="Filter..." value="${filter.replace(/"/g, '&quot;')}">
<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;