v2/status.php aktualisiert

This commit is contained in:
2026-07-28 00:15:21 +02:00
parent 48ffd7df2f
commit 87b8388d94
+145
View File
@@ -0,0 +1,145 @@
<?php
// status.php - API & Frontend in einer Datei
$db_file = __DIR__ . '/status.sqlite';
$pdo = new PDO('sqlite:' . $db_file);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Tabelle erstellen, falls nicht existent
$pdo->exec("CREATE TABLE IF NOT EXISTS nodes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
server TEXT,
client TEXT,
status TEXT,
handshake TEXT,
last_seen DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE(server, client)
)");
// --- TEIL 1: API (Daten empfangen) ---
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$data = json_decode(file_get_contents('php://input'), true);
if ($data && isset($data['server']) && isset($data['client'])) {
$stmt = $pdo->prepare("
INSERT INTO nodes (server, client, status, handshake, last_seen)
VALUES (:server, :client, :status, :handshake, datetime('now'))
ON CONFLICT(server, client)
DO UPDATE SET status=:status, handshake=:handshake, last_seen=datetime('now')
");
$stmt->execute([
':server' => $data['server'],
':client' => $data['client'],
':status' => $data['status'],
':handshake' => $data['handshake']
]);
echo json_encode(["success" => true]);
} else {
http_response_code(400);
echo json_encode(["error" => "Invalid payload"]);
}
exit;
}
// --- TEIL 2: API (Daten für Frontend ausliefern) ---
if (isset($_GET['api'])) {
header('Content-Type: application/json');
$stmt = $pdo->query("SELECT * FROM nodes ORDER BY server, client");
echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC));
exit;
}
// --- TEIL 3: HTML FRONTEND ---
?>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Gateway Status Dashboard</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background-color: #121212;
color: #ffffff;
margin: 0;
padding: 30px;
}
h1 { border-bottom: 2px solid #333; padding-bottom: 10px; margin-bottom: 30px; }
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 20px;
}
.card {
background: #1e1e1e;
padding: 20px;
border-radius: 8px;
border-left: 6px solid #555;
box-shadow: 0 4px 6px rgba(0,0,0,0.3);
transition: transform 0.2s;
}
.card:hover { transform: translateY(-3px); }
.card.online { border-left-color: #00C851; }
.card.offline { border-left-color: #ff4444; }
.card h3 { margin: 0 0 10px 0; font-size: 1.3rem; }
.card p { margin: 6px 0; font-size: 0.9rem; color: #cccccc; }
.server-badge {
display: inline-block;
background: #333;
padding: 3px 8px;
border-radius: 4px;
font-size: 0.75rem;
color: #aaa;
text-transform: uppercase;
letter-spacing: 1px;
margin-bottom: 10px;
}
.time { color: #888; font-size: 0.8rem; margin-top: 15px; }
</style>
</head>
<body>
<h1>🟢 Gateway Status Overview</h1>
<div class="grid" id="node-grid">
<p>Lade Status-Daten...</p>
</div>
<script>
async function fetchStatus() {
try {
const response = await fetch('?api=1');
const data = await response.json();
const grid = document.getElementById('node-grid');
grid.innerHTML = '';
data.forEach(node => {
// Zeitstempel parsen (SQLite liefert UTC)
const lastSeen = new Date(node.last_seen + " UTC");
const now = new Date();
// Differenz in Minuten berechnen
const diffMinutes = (now - lastSeen) / 1000 / 60;
// Node ist online, wenn status="true" UND der letzte Ping nicht älter als 5 Minuten ist
const isOnline = (node.status === 'true' && diffMinutes < 5);
const card = document.createElement('div');
card.className = `card ${isOnline ? 'online' : 'offline'}`;
card.innerHTML = `
<div class="server-badge">${node.server}</div>
<h3>${node.client}</h3>
<p><strong>Handshake:</strong> ${node.handshake}</p>
<p class="time">Update: ${lastSeen.toLocaleTimeString()} (vor ${Math.round(diffMinutes)} Min.)</p>
`;
grid.appendChild(card);
});
} catch (err) {
console.error("Fehler beim Abrufen der Daten:", err);
}
}
fetchStatus();
setInterval(fetchStatus, 30000); // Alle 30 Sekunden aktualisieren
</script>
</body>
</html>