refactor: reorganize directory structure to match exam submission spec

هذا الالتزام موجود في:
mac
2026-07-27 14:14:17 +03:00
الأصل 5419a51265
التزام 23a5119c9d
25 ملفات معدلة مع 34 إضافات و193 حذوفات

عرض الملف

@@ -0,0 +1,163 @@
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<title>Mithal.space Monitoring</title>
<!-- Include Google Fonts and Chart.js -->
<link href="https://fonts.googleapis.com/css2?family=Tajawal:wght@300;400;700&display=swap" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
:root {
--bg: #0a0e17; --card: rgba(16, 24, 39, 0.8);
--text: #e2e8f0; --muted: #64748b;
--accent: #38bdf8; --success: #34d399; --danger: #f87171;
--border: rgba(255, 255, 255, 0.05);
}
body {
font-family: 'Tajawal', sans-serif;
background: var(--bg); color: var(--text);
margin: 0; padding: 40px 20px;
background-image: radial-gradient(circle at top right, rgba(56, 189, 248, 0.1), transparent 40%);
}
h1 { text-align: center; color: var(--accent); margin-bottom: 40px; }
.grid {
display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px; max-width: 1200px; margin: 0 auto 30px auto;
}
.card {
background: var(--card); border: 1px solid var(--border);
border-radius: 16px; padding: 25px;
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
backdrop-filter: blur(10px); transition: transform 0.3s;
}
.card:hover { transform: translateY(-3px); border-color: rgba(56, 189, 248, 0.3); }
.card-title { font-size: 1.1rem; color: var(--muted); margin-bottom: 15px; font-weight: bold; }
.metric-value { font-size: 2.5rem; font-weight: 700; display: flex; align-items: baseline; gap: 8px;}
.unit { font-size: 1.2rem; color: var(--muted); font-weight: normal; }
.good { color: var(--success); } .bad { color: var(--danger); }
table {
width: 100%; border-collapse: collapse; margin-top: 15px;
text-align: right;
}
th, td { padding: 12px 15px; border-bottom: 1px solid var(--border); }
th { color: var(--muted); font-weight: normal; font-size: 0.9rem; }
tr:hover { background: rgba(255,255,255,0.02); }
.chart-container {
max-width: 1200px; margin: 0 auto; background: var(--card);
border-radius: 16px; padding: 25px; border: 1px solid var(--border);
}
</style>
</head>
<body>
<h1>لوحة مراقبة Mithal.space 🚀</h1>
<div class="grid">
<div class="card">
<div class="card-title">نسبة التوافر (Uptime)</div>
<div id="uptime" class="metric-value good">99.9 <span class="unit">%</span></div>
</div>
<div class="card">
<div class="card-title">صلاحية شهادة SSL</div>
<div id="ssl-status" class="metric-value good">64 <span class="unit">يوم متبقي</span></div>
</div>
<div class="card">
<div class="card-title">متوسط الاستجابة</div>
<div id="avg-latency" class="metric-value">120 <span class="unit">ms</span></div>
</div>
</div>
<div class="chart-container">
<div class="card-title">زمن الاستجابة (آخر 60 دقيقة)</div>
<canvas id="latencyChart" height="80"></canvas>
</div>
<div class="grid" style="margin-top: 30px;">
<div class="card" style="grid-column: 1 / -1;">
<div class="card-title">سجل الفحوصات (آخر 10)</div>
<table>
<thead>
<tr>
<th>الوقت</th>
<th>الحالة</th>
<th>الاستجابة (ms)</th>
<th>DNS (ms)</th>
<th>بحث (ms)</th>
</tr>
</thead>
<tbody id="history-table">
<tr><td colspan="5" style="text-align:center; color: var(--muted)">جاري جلب البيانات...</td></tr>
</tbody>
</table>
</div>
</div>
<script>
// Mock data to demonstrate the beautiful UI (since we can't run the backend locally now)
function generateMockData() {
let labels = [];
let data = [];
let now = new Date();
for(let i=60; i>=0; i--) {
let d = new Date(now.getTime() - i*60000);
labels.push(d.getHours() + ':' + d.getMinutes().toString().padStart(2, '0'));
data.push(Math.floor(Math.random() * (150 - 80 + 1)) + 80);
}
return { labels, data };
}
const mock = generateMockData();
const ctx = document.getElementById('latencyChart').getContext('2d');
// Gradient for chart
let gradient = ctx.createLinearGradient(0, 0, 0, 400);
gradient.addColorStop(0, 'rgba(56, 189, 248, 0.5)');
gradient.addColorStop(1, 'rgba(56, 189, 248, 0.0)');
new Chart(ctx, {
type: 'line',
data: {
labels: mock.labels,
datasets: [{
label: 'Latency (ms)',
data: mock.data,
borderColor: '#38bdf8',
backgroundColor: gradient,
borderWidth: 2,
pointRadius: 0,
pointHoverRadius: 5,
fill: true,
tension: 0.4
}]
},
options: {
responsive: true,
plugins: { legend: { display: false } },
scales: {
x: { grid: { color: 'rgba(255,255,255,0.05)' }, ticks: { color: '#64748b' } },
y: { grid: { color: 'rgba(255,255,255,0.05)' }, ticks: { color: '#64748b' } }
}
}
});
// Populate Table with mock data
const tbody = document.getElementById('history-table');
let rows = '';
for(let i=0; i<10; i++) {
rows += `
<tr>
<td>${mock.labels[60-i]}</td>
<td class="good">200 OK</td>
<td>${mock.data[60-i]}</td>
<td>24.5</td>
<td>310.2</td>
</tr>`;
}
tbody.innerHTML = rows;
</script>
</body>
</html>

عرض الملف

@@ -0,0 +1,95 @@
import requests
import time
import socket
import ssl
import json
import os
from datetime import datetime
import dns.resolver
TARGET_URL = "https://mithal.space"
TARGET_DOMAIN = "mithal.space"
DATA_FILE = "/Users/mac/a1/mithal_monitor/data/metrics.json"
def check_ssl(domain):
context = ssl.create_default_context()
try:
with socket.create_connection((domain, 443), timeout=5) as sock:
with context.wrap_socket(sock, server_hostname=domain) as ssock:
cert = ssock.getpeercert()
expiry_date = datetime.strptime(cert['notAfter'], "%b %d %H:%M:%S %Y %Z")
days_remaining = (expiry_date - datetime.utcnow()).days
return "Valid", days_remaining
except Exception as e:
return f"Error: {str(e)}", 0
def check_dns(domain):
start = time.time()
try:
answers = dns.resolver.resolve(domain, 'A')
return round((time.time() - start) * 1000, 2)
except Exception:
return -1
def measure():
results = {
"timestamp": datetime.utcnow().isoformat() + "Z",
"latency_ms": -1,
"status_code": 0,
"uptime": False,
"ssl_status": "Unknown",
"ssl_days": 0,
"dns_time_ms": -1,
"search_time_ms": -1
}
# DNS Check
results["dns_time_ms"] = check_dns(TARGET_DOMAIN)
# SSL Check
ssl_status, ssl_days = check_ssl(TARGET_DOMAIN)
results["ssl_status"] = ssl_status
results["ssl_days"] = ssl_days
# HTTP Check
try:
start = time.time()
resp = requests.get(TARGET_URL, timeout=5)
results["latency_ms"] = round((time.time() - start) * 1000, 2)
results["status_code"] = resp.status_code
results["uptime"] = resp.status_code < 400
except Exception:
pass
# Mock Search Check (assuming a /search endpoint exists)
try:
start = time.time()
requests.get(f"{TARGET_URL}/search?q=test", timeout=5)
results["search_time_ms"] = round((time.time() - start) * 1000, 2)
except Exception:
pass
return results
def save_data(data):
os.makedirs(os.path.dirname(DATA_FILE), exist_ok=True)
history = []
if os.path.exists(DATA_FILE):
try:
with open(DATA_FILE, 'r') as f:
history = json.load(f)
except json.JSONDecodeError:
pass
history.append(data)
# Keep last 1440 checks (24 hours at 1/min)
history = history[-1440:]
with open(DATA_FILE, 'w') as f:
json.dump(history, f, indent=2)
if __name__ == "__main__":
while True:
data = measure()
save_data(data)
time.sleep(60)