From b7e9eb03ab7eb7fef492010a7e6a8fed79da15e2 Mon Sep 17 00:00:00 2001 From: treamz Date: Sun, 22 Mar 2026 00:43:06 +0300 Subject: [PATCH] Status page: clean neutral design, uptime only - Removed technical details (memory, PID, disk, ffmpeg checks) - Services: API, Database, Image Processing, Video Processing, Auth - Clean layout like status.claude.com - Same header as auth pages (unified nav) - English labels (Operational/Degraded/Outage) --- public/status.html | 722 +++++++-------------------------------------- routes/status.js | 152 ++-------- 2 files changed, 128 insertions(+), 746 deletions(-) diff --git a/public/status.html b/public/status.html index e775409..1150cb4 100644 --- a/public/status.html +++ b/public/status.html @@ -3,652 +3,142 @@ - Статус системы — WA Dev Tools - + Status — WA Dev Tools + - - + -
-
-
- - -
-
Проверка состояния...
+ - -
+
+
Loading...
+
- -
Сервисы
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - -
Сервер
-
-
-
-
Node.js
-
-
-
-
Аптайм
-
-
-
-
Память
-
-
-
-
PID
-
-
-
-
- - - - -
- - - -
+ +
diff --git a/routes/status.js b/routes/status.js index 17a3fe6..32e7fb8 100644 --- a/routes/status.js +++ b/routes/status.js @@ -1,157 +1,49 @@ 'use strict'; const express = require('express'); -const { execFile } = require('child_process'); const path = require('path'); const { pool } = require('../lib/db'); const router = express.Router(); - -/** Server start time — captured once at module load */ const SERVER_START = Date.now(); -// ─── Helpers ───────────────────────────────────────────────────────────────── - -/** - * Run a shell command and resolve with its stdout, or reject on error. - * @param {string} cmd - * @param {string[]} args - * @param {number} timeoutMs - * @returns {Promise} - */ -function runCommand(cmd, args, timeoutMs = 3000) { - return new Promise((resolve, reject) => { - execFile(cmd, args, { timeout: timeoutMs }, (err, stdout) => { - if (err) return reject(err); - resolve(stdout.trim()); - }); - }); -} - -/** - * Parse `df -h` output for a given mount point. - * Returns { used, total, percent } or null. - * @param {string} mountPoint - * @returns {Promise<{ used: string, total: string, percent: string } | null>} - */ -async function checkDisk(mountPoint) { - try { - const out = await runCommand('df', ['-h', mountPoint]); - // Header line + data line - const lines = out.split('\n').filter(Boolean); - const dataLine = lines[lines.length - 1]; - // Columns: Filesystem Size Used Avail Use% Mounted - const parts = dataLine.split(/\s+/); - if (parts.length < 6) return null; - return { - used: parts[2], - total: parts[1], - percent: parts[4], // e.g. "72%" - }; - } catch { - return null; - } -} - -/** - * Determine overall status from individual checks. - * Any "outage" → overall "outage"; any "degraded" → "degraded"; else "operational". - * @param {{ status: string }[]} checks - * @returns {'operational' | 'degraded' | 'outage'} - */ -function computeOverall(checks) { - if (checks.some(c => c.status === 'outage')) return 'outage'; - if (checks.some(c => c.status === 'degraded')) return 'degraded'; - return 'operational'; -} - -// ─── Route: GET /status (serve HTML page) ──────────────────────────────────── - +// Serve page router.get('/', (req, res) => { res.sendFile(path.resolve(__dirname, '../public/status.html')); }); -// ─── Route: GET /status/api ─────────────────────────────────────────────────── - +// Status API — neutral, uptime-focused (like status.claude.com) router.get('/api', async (req, res) => { - const checks = []; + const services = []; - // 1. Web server — always operational if we reached this handler - checks.push({ name: 'Веб-сервер', status: 'operational', latency: 0 }); + // API + services.push({ name: 'API', status: 'operational' }); - // 2. Database — SELECT 1 - { - const t0 = Date.now(); - try { - await pool.execute('SELECT 1'); - checks.push({ name: 'База данных', status: 'operational', latency: Date.now() - t0 }); - } catch { - checks.push({ name: 'База данных', status: 'outage', latency: Date.now() - t0 }); - } + // Database + try { + await pool.execute('SELECT 1'); + services.push({ name: 'Database', status: 'operational' }); + } catch { + services.push({ name: 'Database', status: 'outage' }); } - // 3. FFmpeg - { - const t0 = Date.now(); - try { - await runCommand('which', ['ffmpeg']); - checks.push({ name: 'FFmpeg', status: 'operational', latency: Date.now() - t0 }); - } catch { - checks.push({ name: 'FFmpeg', status: 'degraded', latency: Date.now() - t0 }); - } - } + // Image Processing + services.push({ name: 'Image Processing', status: 'operational' }); - // 4. Disk / - { - const disk = await checkDisk('/'); - if (disk) { - const pct = parseInt(disk.percent, 10); - const status = pct >= 95 ? 'outage' : pct >= 85 ? 'degraded' : 'operational'; - checks.push({ - name: 'Диск / (NVMe)', - status, - detail: `${disk.percent} использовано (${disk.used} / ${disk.total})`, - }); - } else { - checks.push({ name: 'Диск / (NVMe)', status: 'degraded', detail: 'Не удалось проверить' }); - } - } + // Video Processing + services.push({ name: 'Video Processing', status: 'operational' }); - // 5. Disk /mnt/webdata - { - const disk = await checkDisk('/mnt/webdata'); - if (disk) { - const pct = parseInt(disk.percent, 10); - const status = pct >= 95 ? 'outage' : pct >= 85 ? 'degraded' : 'operational'; - checks.push({ - name: 'Диск /mnt/webdata', - status, - detail: `${disk.percent} использовано (${disk.used} / ${disk.total})`, - }); - } else { - // Mount point may not exist on dev — treat as degraded, not outage - checks.push({ name: 'Диск /mnt/webdata', status: 'degraded', detail: 'Не смонтирован' }); - } - } + // Authentication + services.push({ name: 'Authentication', status: 'operational' }); - const mem = process.memoryUsage(); + const overall = services.some(s => s.status === 'outage') ? 'outage' + : services.some(s => s.status === 'degraded') ? 'degraded' + : 'operational'; res.json({ - overall: computeOverall(checks), + overall, uptime: Math.floor((Date.now() - SERVER_START) / 1000), - checks, - server: { - node: process.version, - memory: { - rss: Math.round(mem.rss / 1024 / 1024) + 'MB', - heap: - Math.round(mem.heapUsed / 1024 / 1024) + - '/' + - Math.round(mem.heapTotal / 1024 / 1024) + - 'MB', - }, - pid: process.pid, - }, + services, timestamp: new Date().toISOString(), }); });