UptimeMonitor
This commit is contained in:
parent
4fdf45d69d
commit
a9d9df7775
@ -28,13 +28,46 @@ function ping($url) {
|
||||
}
|
||||
|
||||
function notifyStatusChange($url, $oldStatus, $newStatus, $error = null) {
|
||||
$recipient = 'yumeecute@aol.com';
|
||||
$time = date('Y-m-d H:i:s');
|
||||
$statusEmoji = ($newStatus === 'error') ? '🚨' : '🟢';
|
||||
$statusText = strtoupper($newStatus);
|
||||
|
||||
// 1. Send Telegram Push to Phone (24/7 real-time forcing)
|
||||
try {
|
||||
$stmt = db()->query("SELECT value FROM settings WHERE `key` = 'telegram_token'");
|
||||
$token = $stmt->fetchColumn();
|
||||
|
||||
$stmt2 = db()->query("SELECT value FROM settings WHERE `key` = 'telegram_chat_id'");
|
||||
$chatId = $stmt2->fetchColumn();
|
||||
|
||||
if ($token && $chatId) {
|
||||
$msg = "$statusEmoji *MONITOR ALERT*
|
||||
URL: $url
|
||||
Status: *$statusText*
|
||||
Time: $time
|
||||
" . ($error ? "Error: $error" : "");
|
||||
$tgUrl = "https://api.telegram.org/bot$token/sendMessage";
|
||||
$data = ['chat_id' => $chatId, 'text' => $msg, 'parse_mode' => 'Markdown'];
|
||||
$options = [
|
||||
'http' => [
|
||||
'header' => "Content-type: application/x-www-form-urlencoded
|
||||
",
|
||||
'method' => 'POST',
|
||||
'content' => http_build_query($data),
|
||||
],
|
||||
];
|
||||
file_get_contents($tgUrl, false, stream_context_create($options));
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// Ignore errors if telegram not setup
|
||||
}
|
||||
|
||||
// 2. Original Email logic
|
||||
$recipient = 'yumeecute@aol.com';
|
||||
|
||||
if ($oldStatus === 'ok' && $newStatus === 'error') {
|
||||
$subject = "🔴 ALERT: Website Down - $url";
|
||||
$html = "
|
||||
<div style='font-family: Arial, sans-serif; border: 1px solid #ff4d4d; padding: 20px; border-radius: 8px;'>
|
||||
$html = <div style='font-family: Arial, sans-serif; border: 1px solid #ff4d4d; padding: 20px; border-radius: 8px;'>
|
||||
<h2 style='color: #ff4d4d;'>Website Down Alert</h2>
|
||||
<p>The following website is currently unresponsive:</p>
|
||||
<p><strong>URL:</strong> <a href='$url'>$url</a></p>
|
||||
@ -46,8 +79,7 @@ function notifyStatusChange($url, $oldStatus, $newStatus, $error = null) {
|
||||
";
|
||||
} elseif ($oldStatus === 'error' && $newStatus === 'ok') {
|
||||
$subject = "🟢 RESOLVED: Website Up - $url";
|
||||
$html = "
|
||||
<div style='font-family: Arial, sans-serif; border: 1px solid #28a745; padding: 20px; border-radius: 8px;'>
|
||||
$html = <div style='font-family: Arial, sans-serif; border: 1px solid #28a745; padding: 20px; border-radius: 8px;'>
|
||||
<h2 style='color: #28a745;'>Website Back Online</h2>
|
||||
<p>The following website is responding normally again:</p>
|
||||
<p><strong>URL:</strong> <a href='$url'>$url</a></p>
|
||||
@ -79,6 +111,30 @@ function generateApiKey() {
|
||||
}
|
||||
|
||||
switch ($action) {
|
||||
|
||||
case 'save_telegram':
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$token = $data['telegram_token'] ?? '';
|
||||
$chatId = $data['telegram_chat_id'] ?? '';
|
||||
|
||||
$stmt = db()->prepare("INSERT INTO settings (`key`, value) VALUES ('telegram_token', ?) ON DUPLICATE KEY UPDATE value = VALUES(value)");
|
||||
$stmt->execute([$token]);
|
||||
|
||||
$stmt = db()->prepare("INSERT INTO settings (`key`, value) VALUES ('telegram_chat_id', ?) ON DUPLICATE KEY UPDATE value = VALUES(value)");
|
||||
$stmt->execute([$chatId]);
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
break;
|
||||
|
||||
case 'get_telegram':
|
||||
$stmt = db()->query("SELECT `key`, value FROM settings WHERE `key` IN ('telegram_token', 'telegram_chat_id')");
|
||||
$res = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
|
||||
echo json_encode([
|
||||
'telegram_token' => $res['telegram_token'] ?? '',
|
||||
'telegram_chat_id' => $res['telegram_chat_id'] ?? ''
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'settings':
|
||||
echo json_encode(['monitoring_enabled' => isMonitoringEnabled()]);
|
||||
break;
|
||||
|
||||
47
backend_monitor.php
Normal file
47
backend_monitor.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/api/uptime.php';
|
||||
|
||||
// A simple CLI script that runs continuously on the server
|
||||
// Usage: php backend_monitor.php &
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
die("This script must be run from the command line.");
|
||||
}
|
||||
|
||||
echo "Starting 24/7 Flatlogic Backend Monitor...\n";
|
||||
echo "Monitoring URLs every 2 seconds...\n";
|
||||
|
||||
while (true) {
|
||||
if (isMonitoringEnabled()) {
|
||||
$stmt = db()->query("SELECT * FROM urls WHERE is_active = 1");
|
||||
$urls = $stmt->fetchAll();
|
||||
|
||||
foreach ($urls as $row) {
|
||||
$res = ping($row['url']);
|
||||
|
||||
// Log latency to ensure history exists
|
||||
$ins = db()->prepare("INSERT INTO uptime_logs (url_id, status, latency) VALUES (?, ?, ?)");
|
||||
$ins->execute([$row['id'], $res['status'], $res['latency']]);
|
||||
|
||||
// Notify on change
|
||||
notifyStatusChange($row['url'], $row['last_status'], $res['status'], $res['error']);
|
||||
|
||||
// Update URL status
|
||||
$upd = db()->prepare("UPDATE urls SET last_status = ?, last_latency = ?, last_checked_at = NOW() WHERE id = ?");
|
||||
$upd->execute([$res['status'], $res['latency'], $row['id']]);
|
||||
|
||||
// Keep only last 500 logs per URL to save DB space
|
||||
$del = db()->prepare(
|
||||
"DELETE FROM uptime_logs
|
||||
WHERE url_id = ?
|
||||
AND id NOT IN (
|
||||
SELECT id FROM (
|
||||
SELECT id FROM uptime_logs WHERE url_id = ? ORDER BY id DESC LIMIT 500
|
||||
) foo
|
||||
)"
|
||||
);
|
||||
$del->execute([$row['id'], $row['id']]);
|
||||
}
|
||||
}
|
||||
sleep(2); // Wait 2 seconds before the next check
|
||||
}
|
||||
|
||||
90
index.php
90
index.php
@ -176,7 +176,8 @@ $v = time(); // Cache busting version
|
||||
<li class="nav-item active" onclick="showSection('dashboard')"><span>📊</span> Dashboard</li>
|
||||
<li class="nav-item" onclick="showSection('monitors')"><span>🔍</span> Monitors</li>
|
||||
<li class="nav-item" onclick="showSection('teams')"><span>👥</span> Team</li>
|
||||
<li class="nav-item" onclick="showSection('api')"><span>🔑</span> API</li>
|
||||
<li class="nav-item" onclick="showSection('api')"><span>🔑</span> API</li>
|
||||
<li class="nav-item" onclick="showSection('telegram')"><span>📱</span> Mobile Push</li>
|
||||
</ul>
|
||||
<div style="padding: 1rem; border-top: 1px solid var(--border);">
|
||||
<button class="btn-glow" style="width:100%; margin-bottom:10px;" onclick="enterMobileMonitor()">📱 FULL VIEW</button>
|
||||
@ -267,7 +268,29 @@ $v = time(); // Cache busting version
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div id="api" class="section">
|
||||
|
||||
<!-- TELEGRAM PUSH SECTION -->
|
||||
<div id="telegram" class="section">
|
||||
<div class="card" style="text-align: left; padding: 2rem;">
|
||||
<h3 style="margin-top:0;">📱 Mobile Push Notifications (24/7)</h3>
|
||||
<p>Aplikasi ini berjalan <b>online 24/7 di server Flatlogic</b>. Untuk memaksa memunculkan notifikasi (wget monitor) langsung ke handphone Anda walau browser tertutup, hubungkan Telegram Bot Anda.</p>
|
||||
|
||||
<div style="margin: 1.5rem 0; display:flex; flex-direction:column; gap:10px;">
|
||||
<input type="text" id="tg_token" class="input-field" placeholder="Bot Token (e.g. 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11)">
|
||||
<input type="text" id="tg_chat_id" class="input-field" placeholder="Chat ID (e.g. 123456789)">
|
||||
<button class="btn" onclick="saveTelegram()">Save Telegram Push Settings</button>
|
||||
</div>
|
||||
|
||||
<div style="font-size:0.85rem; opacity:0.8; background:rgba(0,0,0,0.2); padding:1rem; border-radius:8px;">
|
||||
<b style="color:var(--accent);">Cara Setup:</b><br>
|
||||
1. Buka Telegram, cari <b>@BotFather</b>, ketik <code>/newbot</code> lalu copy Token-nya.<br>
|
||||
2. Ketik nama bot Anda di kolom pencarian Telegram dan Start.<br>
|
||||
3. Buka browser: <code>https://api.telegram.org/bot<TOKEN_ANDA>/getUpdates</code> untuk menemukan <b>"chat":{"id":123456789}</b> Anda.<br>
|
||||
4. Masukkan Token dan Chat ID di atas lalu Save. <b>Server akan mem-push pesan 🚨 ERROR & 🟢 RUN otomatis ke handphone Anda!</b>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="api" class="section">
|
||||
<div class="card" style="margin-bottom: 20px;">
|
||||
<h3>Generate API Key</h3>
|
||||
<div style="display:flex; gap: 10px;">
|
||||
@ -308,7 +331,8 @@ $v = time(); // Cache busting version
|
||||
|
||||
<script>
|
||||
|
||||
let audioAlert = new Audio('https://assets.mixkit.co/active_storage/sfx/2869/2869-preview.mp3');
|
||||
let audioAlertError = new Audio('https://assets.mixkit.co/active_storage/sfx/995/995-preview.mp3'); // Sirene / Alert
|
||||
let audioAlertRun = new Audio('https://assets.mixkit.co/active_storage/sfx/1435/1435-preview.mp3'); // Chime / Success
|
||||
let previousStatuses = {};
|
||||
|
||||
if ("Notification" in window && Notification.permission !== "granted" && Notification.permission !== "denied") {
|
||||
@ -317,20 +341,32 @@ $v = time(); // Cache busting version
|
||||
|
||||
async function checkNotifications(assets) {
|
||||
for (const u of assets) {
|
||||
if (previousStatuses[u.id] && previousStatuses[u.id] !== u.last_status) {
|
||||
// First run: just set the status so it doesn't alert immediately
|
||||
if (!previousStatuses.hasOwnProperty(u.id)) {
|
||||
previousStatuses[u.id] = u.last_status;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (previousStatuses[u.id] !== u.last_status) {
|
||||
if (u.last_status === 'error') {
|
||||
if ("Notification" in window && Notification.permission === "granted") {
|
||||
new Notification("🔴 Alert: Monitor Down!", { body: u.url + " is offline!" });
|
||||
new Notification("🚨 ALARM: MONITOR ERROR!", {
|
||||
body: `[ DOWN ] ${u.url} is offline/error!`,
|
||||
icon: 'https://cdn-icons-png.flaticon.com/512/190/190406.png'
|
||||
});
|
||||
}
|
||||
audioAlert.play().catch(e => console.log('Audio play failed', e));
|
||||
audioAlertError.play().catch(e => console.log('Audio error failed', e));
|
||||
} else if (u.last_status === 'ok') {
|
||||
if ("Notification" in window && Notification.permission === "granted") {
|
||||
new Notification("🟢 Alert: Monitor Up!", { body: u.url + " is back online!" });
|
||||
new Notification("✅ INFO: MONITOR RUN!", {
|
||||
body: `[ RUN ] ${u.url} is back online!`,
|
||||
icon: 'https://cdn-icons-png.flaticon.com/512/190/190411.png'
|
||||
});
|
||||
}
|
||||
audioAlert.play().catch(e => console.log('Audio play failed', e));
|
||||
audioAlertRun.play().catch(e => console.log('Audio run failed', e));
|
||||
}
|
||||
previousStatuses[u.id] = u.last_status;
|
||||
}
|
||||
previousStatuses[u.id] = u.last_status;
|
||||
}
|
||||
}
|
||||
|
||||
@ -529,7 +565,8 @@ $v = time(); // Cache busting version
|
||||
}
|
||||
}
|
||||
|
||||
function showSection(id) {
|
||||
|
||||
function showSection(id) {
|
||||
document.querySelectorAll('.section').forEach(s => s.classList.remove('active'));
|
||||
const sec = document.getElementById(id);
|
||||
if (sec) sec.classList.add('active');
|
||||
@ -537,10 +574,43 @@ $v = time(); // Cache busting version
|
||||
|
||||
if (id === 'teams') fetchTeams();
|
||||
if (id === 'api') fetchApiKeys();
|
||||
if (id === 'telegram') fetchTelegram();
|
||||
|
||||
refreshData();
|
||||
}
|
||||
|
||||
async function fetchTelegram() {
|
||||
try {
|
||||
const res = await fetch('api/uptime.php?action=get_telegram');
|
||||
const data = await res.json();
|
||||
document.getElementById('tg_token').value = data.telegram_token || '';
|
||||
document.getElementById('tg_chat_id').value = data.telegram_chat_id || '';
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
async function saveTelegram() {
|
||||
const token = document.getElementById('tg_token').value;
|
||||
const chatId = document.getElementById('tg_chat_id').value;
|
||||
try {
|
||||
const res = await fetch('api/uptime.php?action=save_telegram', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({ telegram_token: token, telegram_chat_id: chatId })
|
||||
});
|
||||
const data = await res.json();
|
||||
if (data.success) {
|
||||
alert('Telegram Settings Saved! Handphone kamu akan menerima notifikasi 24/7 sekarang.');
|
||||
} else {
|
||||
alert('Failed to save.');
|
||||
}
|
||||
} catch (e) {
|
||||
alert('Error saving settings.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
setInterval(() => {
|
||||
const time = new Date().toISOString().split('T')[1].split('.')[0];
|
||||
document.getElementById('clock').innerText = time + ' UTC';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user