Standalone app for Q5 deployment

هذا الالتزام موجود في:
2026-07-28 13:31:34 +03:00
التزام 79c2b0d2ce
5 ملفات معدلة مع 206 إضافات و0 حذوفات

15
Dockerfile Normal file
عرض الملف

@@ -0,0 +1,15 @@
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY monitor.py .
COPY dashboard.html .
COPY start.sh .
RUN chmod +x start.sh
EXPOSE 8080
CMD ["./start.sh"]

102
dashboard.html Normal file
عرض الملف

@@ -0,0 +1,102 @@
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<title>مراقبة mithal.space</title>
<style>
body { font-family: Arial; background: #0f172a; color: #e2e8f0; padding: 30px; }
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 15px; margin-bottom: 20px; }
.card { background: #1e293b; padding: 20px; border-radius: 10px; }
.big { font-size: 28px; font-weight: bold; }
.status-up { color: #22c55e; }
.status-down { color: #ef4444; }
canvas { background: #1e293b; border-radius: 10px; padding: 10px; }
table { width: 100%; border-collapse: collapse; margin-top: 10px; }
td, th { padding: 8px; border-bottom: 1px solid #334155; text-align: right; font-size: 13px; }
</style>
</head>
<body>
<h1>لوحة مراقبة mithal.space</h1>
<div class="grid">
<div class="card">
<div>نسبة التشغيل (24 ساعة)</div>
<div class="big" id="uptime-pct">-</div>
</div>
<div class="card">
<div>حالة SSL</div>
<div class="big" id="ssl-status">-</div>
</div>
<div class="card">
<div>آخر زمن استجابة</div>
<div class="big" id="latest-latency">-</div>
</div>
</div>
<div class="card">
<div>زمن الاستجابة — آخر ساعة</div>
<canvas id="latencyChart" height="80"></canvas>
</div>
<div class="card" style="margin-top:15px;">
<h3>آخر 10 فحوصات</h3>
<table id="log-table">
<thead><tr><th>الوقت</th><th>الحالة</th><th>الاستجابة</th><th>SSL</th><th>DNS</th></tr></thead>
<tbody></tbody>
</table>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.0/chart.umd.min.js"></script>
<script>
let chart;
async function loadData() {
const res = await fetch('mithal_monitor_log.json');
const text = await res.text();
const lines = text.trim().split('\n').filter(Boolean).map(JSON.parse);
const last = lines[lines.length - 1];
const upCount = lines.filter(l => l.uptime.up).length;
const uptimePct = ((upCount / lines.length) * 100).toFixed(1);
document.getElementById('uptime-pct').innerHTML =
`<span class="${uptimePct > 95 ? 'status-up' : 'status-down'}">${uptimePct}%</span>`;
document.getElementById('ssl-status').innerHTML = last.ssl.valid
? `<span class="status-up">صالحة (${last.ssl.days_until_expiry} يوم)</span>`
: `<span class="status-down">غير صالحة</span>`;
document.getElementById('latest-latency').innerText = last.uptime.latency_ms + ' ms';
const recent = lines.slice(-60);
const labels = recent.map(l => new Date(l.timestamp).toLocaleTimeString('ar-EG'));
const data = recent.map(l => l.uptime.latency_ms);
if (chart) {
chart.data.labels = labels;
chart.data.datasets[0].data = data;
chart.update();
} else {
chart = new Chart(document.getElementById('latencyChart'), {
type: 'line',
data: { labels, datasets: [{ label: 'ms', data, borderColor: '#38bdf8', tension: 0.3 }] },
options: { plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true } } }
});
}
const tbody = document.querySelector('#log-table tbody');
tbody.innerHTML = '';
lines.slice(-10).reverse().forEach(l => {
tbody.innerHTML += `<tr>
<td>${new Date(l.timestamp).toLocaleTimeString('ar-EG')}</td>
<td>${l.uptime.up ? '✅' : '❌'}</td>
<td>${l.uptime.latency_ms} ms</td>
<td>${l.ssl.valid ? '✅' : '❌'}</td>
<td>${l.dns.dns_time_ms} ms</td>
</tr>`;
});
}
loadData();
setInterval(loadData, 60000);
</script>
</body>
</html>

84
monitor.py Executable file
عرض الملف

@@ -0,0 +1,84 @@
import requests
import socket
import ssl
import time
import json
from datetime import datetime, timezone
from urllib.parse import urlparse
TARGET_URL = "https://mithal.space"
SEARCH_URL = "https://mithal.space/search?q=test"
LOG_FILE = "mithal_monitor_log.json"
CHECK_INTERVAL = 60
def check_latency_and_uptime(url):
try:
start = time.time()
response = requests.get(url, timeout=10)
latency_ms = round((time.time() - start) * 1000, 2)
return {
"up": response.status_code < 500,
"status_code": response.status_code,
"latency_ms": latency_ms
}
except requests.exceptions.RequestException as e:
return {"up": False, "status_code": None, "latency_ms": None, "error": str(e)}
def check_ssl(hostname):
try:
context = ssl.create_default_context()
with socket.create_connection((hostname, 443), timeout=10) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
cert = ssock.getpeercert()
expiry_str = cert['notAfter']
expiry_date = datetime.strptime(expiry_str, '%b %d %H:%M:%S %Y %Z')
days_left = (expiry_date - datetime.utcnow()).days
return {"valid": True, "days_until_expiry": days_left}
except Exception as e:
return {"valid": False, "error": str(e)}
def check_dns(hostname):
try:
start = time.time()
socket.gethostbyname(hostname)
dns_time_ms = round((time.time() - start) * 1000, 2)
return {"resolved": True, "dns_time_ms": dns_time_ms}
except Exception as e:
return {"resolved": False, "error": str(e)}
def check_search_response(url):
try:
start = time.time()
response = requests.get(url, timeout=10)
latency_ms = round((time.time() - start) * 1000, 2)
return {"success": response.status_code == 200, "latency_ms": latency_ms}
except requests.exceptions.RequestException as e:
return {"success": False, "error": str(e)}
def run_check():
hostname = urlparse(TARGET_URL).hostname
result = {
"timestamp": datetime.now(timezone.utc).isoformat(),
"uptime": check_latency_and_uptime(TARGET_URL),
"ssl": check_ssl(hostname),
"dns": check_dns(hostname),
"search": check_search_response(SEARCH_URL)
}
with open(LOG_FILE, "a") as f:
f.write(json.dumps(result) + "\n")
print(f"[{result['timestamp']}] Check complete — up: {result['uptime']['up']}")
return result
if __name__ == "__main__":
while True:
run_check()
time.sleep(CHECK_INTERVAL)

2
requirements.txt Normal file
عرض الملف

@@ -0,0 +1,2 @@
requests
dnspython

3
start.sh Executable file
عرض الملف

@@ -0,0 +1,3 @@
#!/bin/sh
python3 monitor.py &
python3 -m http.server 8080