adding task files

هذا الالتزام موجود في:
2026-07-29 20:39:34 +00:00
الأصل 87e6534761
التزام 31cba2e547
24 ملفات معدلة مع 1756 إضافات و0 حذوفات

عرض الملف

@@ -0,0 +1,21 @@
FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir \
--prefix=/install \
-r requirements.txt
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /install /usr/local
COPY . .
EXPOSE 8000
CMD ["python3", "-m", "http.server", "8000", "--directory", "/app"]

230
q5-mithal-monitor/app.js Normal file
عرض الملف

@@ -0,0 +1,230 @@
let chart = null;
async function loadData() {
try {
const response = await fetch("../metrics.csv?t=" + Date.now());
const text = await response.text();
let rows = text.trim().split("\n");
if (rows.length <= 1) return;
// Remove CSV header
rows.shift();
const data = rows
.map(row => row.split(","))
.filter(row => row.length >= 7);
const history = document.getElementById("history");
history.innerHTML = "";
const now = new Date();
// ==========================
// Uptime (24h)
// ==========================
const last24 = data.filter(row => {
const t = new Date(row[0].replace(" ", "T"));
return (now - t) <= (24 * 60 * 60 * 1000);
});
const up = last24.filter(row => row[2] === "200").length;
const uptime =
last24.length === 0
? 0
: ((up / last24.length) * 100).toFixed(2);
document.getElementById("uptime").textContent = uptime + "%";
// ==========================
// SSL Status
// ==========================
const latest = data[data.length - 1];
document.getElementById("ssl").textContent =
latest[5] + " Days Remaining";
// ==========================
// Chart
// ==========================
let labels = [];
let values = [];
data.forEach(row => {
const latency = parseFloat(row[1]);
// Ignore abnormal values
if (latency <= 500) {
labels.push(row[0].split(" ")[1]);
values.push(latency);
}
});
drawChart(labels, values);
// ==========================
// Last 10 Checks
// ==========================
data.slice(-10).reverse().forEach(row => {
const status = row[2] === "200";
history.innerHTML += `
<tr>
<td>${row[0]}</td>
<td class="${status ? "up" : "down"}">
${status ? "UP" : "DOWN"}
</td>
<td>${row[1]} ms</td>
<td>${row[3]} ms</td>
<td>${row[6]} ms</td>
<td>${row[5]} Days</td>
</tr>
`;
});
}
catch (err) {
console.error("Dashboard Error:", err);
}
}
function drawChart(labels, values) {
const canvas = document.getElementById("latencyChart");
if (!canvas) return;
if (chart) {
chart.destroy();
}
chart = new Chart(canvas, {
type: "line",
data: {
labels: labels,
datasets: [
{
label: "Latency (ms)",
data: values,
borderColor: "#3498db",
backgroundColor: "rgba(52,152,219,0.15)",
borderWidth: 2,
fill: true,
tension: 0.3,
pointRadius: 3,
pointHoverRadius: 5
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
animation: false,
plugins: {
legend: {
display: true
}
},
scales: {
y: {
min: 0,
max: 250,
title: {
display: true,
text: "Milliseconds"
}
},
x: {
title: {
display: true,
text: "Time"
}
}
}
}
});
}
loadData();

عرض الملف

@@ -0,0 +1,84 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mithal Monitoring Dashboard</title>
<link rel="stylesheet" href="style.css?v=3">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<div class="container">
<h1>Mithal Monitoring Dashboard</h1>
<div class="cards">
<div class="card">
<h3>Uptime (24h)</h3>
<h2 id="uptime">0%</h2>
</div>
<div class="card">
<h3>SSL Status</h3>
<h2 id="ssl">Loading...</h2>
</div>
</div>
<div class="chart-container">
<canvas id="latencyChart"></canvas>
</div>
<div class="table-container">
<h2>Last 10 Checks</h2>
<table>
<thead>
<tr>
<th>Time</th>
<th>Status</th>
<th>Latency</th>
<th>DNS</th>
<th>Search</th>
<th>SSL Days</th>
</tr>
</thead>
<tbody id="history">
</tbody>
</table>
</div>
</div>
<script src="app.js?v=3"></script>
</body>

عرض الملف

@@ -0,0 +1,53 @@
Timestamp,Latency(ms),Status,DNS(ms),SSL Expiry,Days Left,Search(ms)
2026-07-29 12:29:42,86.56,200,1.24,2026-09-15,48,77.74
2026-07-29 13:02:47,115.84,200,0.63,2026-09-15,48,76.28
2026-07-29 13:03:48,77.67,200,0.35,2026-09-15,48,75.12
2026-07-29 13:04:48,81.49,200,0.94,2026-09-15,48,83.27
2026-07-29 13:05:48,76.87,200,0.88,2026-09-15,48,79.01
2026-07-29 13:06:48,105.08,200,0.47,2026-09-15,48,75.93
2026-07-29 13:07:49,91.23,200,0.39,2026-09-15,48,74.53
2026-07-29 13:08:49,87.99,200,0.38,2026-09-15,48,86.44
2026-07-29 13:09:49,78.44,200,0.6,2026-09-15,48,78.73
2026-07-29 13:10:50,75.26,200,0.45,2026-09-15,47,75.22
2026-07-29 13:11:50,78.65,200,0.4,2026-09-15,47,78.07
2026-07-29 13:12:50,82.63,200,0.31,2026-09-15,47,98.73
2026-07-29 13:13:50,76.69,200,0.38,2026-09-15,47,76.14
2026-07-29 13:14:51,78.32,200,0.29,2026-09-15,47,79.26
2026-07-29 13:15:51,78.01,200,0.34,2026-09-15,47,77.86
2026-07-29 13:16:51,78.61,200,2.42,2026-09-15,47,75.91
2026-07-29 13:17:51,112.39,200,0.39,2026-09-15,47,78.11
2026-07-29 13:18:52,76.81,200,3.9,2026-09-15,47,79.26
2026-07-29 13:19:52,76.79,200,0.29,2026-09-15,47,81.39
2026-07-29 13:20:52,81.92,200,0.38,2026-09-15,47,81.31
2026-07-29 13:21:52,79.67,200,0.39,2026-09-15,47,75.22
2026-07-29 13:22:53,91.11,200,0.35,2026-09-15,47,77.56
2026-07-29 13:23:53,85.6,200,4.12,2026-09-15,47,75.11
2026-07-29 13:24:53,79.27,200,0.36,2026-09-15,47,80.63
2026-07-29 13:25:53,77.88,200,0.32,2026-09-15,47,82.34
2026-07-29 13:26:54,79.35,200,0.49,2026-09-15,47,74.78
2026-07-29 13:27:54,96.65,200,0.37,2026-09-15,47,75.99
2026-07-29 13:28:54,81.67,200,1.55,2026-09-15,47,72.96
2026-07-29 13:29:54,96.08,200,4.82,2026-09-15,47,77.69
2026-07-29 13:30:56,931.52,200,0.33,2026-09-15,47,83.28
2026-07-29 13:31:56,80.81,200,1.11,2026-09-15,47,79.18
2026-07-29 13:32:56,156.07,200,0.5,2026-09-15,47,77.07
2026-07-29 13:35:19,84.33,200,1.81,2026-09-15,47,89.93
2026-07-29 13:36:20,82.3,200,0.45,2026-09-15,47,76.14
2026-07-29 13:37:20,81.27,200,0.38,2026-09-15,47,78.65
2026-07-29 13:38:20,176.09,200,0.53,2026-09-15,47,102.99
2026-07-29 13:46:29,92.47,200,0.31,2026-09-15,47,73.5
2026-07-29 13:47:29,79.73,200,0.32,2026-09-15,47,79.24
2026-07-29 13:48:29,76.52,200,0.64,2026-09-15,47,79.0
2026-07-29 13:49:29,80.01,200,0.55,2026-09-15,47,78.53
2026-07-29 13:50:30,78.15,200,1.62,2026-09-15,47,75.87
2026-07-29 13:51:30,135.51,200,0.43,2026-09-15,47,79.1
2026-07-29 13:52:30,75.61,200,0.36,2026-09-15,47,77.5
2026-07-29 13:53:31,77.33,200,0.38,2026-09-15,47,120.55
2026-07-29 13:54:31,77.05,200,0.57,2026-09-15,47,77.96
2026-07-29 13:55:31,78.7,200,0.4,2026-09-15,47,72.49
2026-07-29 13:56:31,100.53,200,0.36,2026-09-15,47,76.88
2026-07-29 13:57:32,82.96,200,0.38,2026-09-15,47,86.56
2026-07-29 13:58:32,96.16,200,0.45,2026-09-15,47,74.9
2026-07-29 13:59:32,79.9,200,0.32,2026-09-15,47,74.98
2026-07-29 14:00:32,80.24,200,1.81,2026-09-15,47,73.09
2026-07-29 14:01:33,130.87,200,0.35,2026-09-15,47,76.39
1 Timestamp Latency(ms) Status DNS(ms) SSL Expiry Days Left Search(ms)
2 2026-07-29 12:29:42 86.56 200 1.24 2026-09-15 48 77.74
3 2026-07-29 13:02:47 115.84 200 0.63 2026-09-15 48 76.28
4 2026-07-29 13:03:48 77.67 200 0.35 2026-09-15 48 75.12
5 2026-07-29 13:04:48 81.49 200 0.94 2026-09-15 48 83.27
6 2026-07-29 13:05:48 76.87 200 0.88 2026-09-15 48 79.01
7 2026-07-29 13:06:48 105.08 200 0.47 2026-09-15 48 75.93
8 2026-07-29 13:07:49 91.23 200 0.39 2026-09-15 48 74.53
9 2026-07-29 13:08:49 87.99 200 0.38 2026-09-15 48 86.44
10 2026-07-29 13:09:49 78.44 200 0.6 2026-09-15 48 78.73
11 2026-07-29 13:10:50 75.26 200 0.45 2026-09-15 47 75.22
12 2026-07-29 13:11:50 78.65 200 0.4 2026-09-15 47 78.07
13 2026-07-29 13:12:50 82.63 200 0.31 2026-09-15 47 98.73
14 2026-07-29 13:13:50 76.69 200 0.38 2026-09-15 47 76.14
15 2026-07-29 13:14:51 78.32 200 0.29 2026-09-15 47 79.26
16 2026-07-29 13:15:51 78.01 200 0.34 2026-09-15 47 77.86
17 2026-07-29 13:16:51 78.61 200 2.42 2026-09-15 47 75.91
18 2026-07-29 13:17:51 112.39 200 0.39 2026-09-15 47 78.11
19 2026-07-29 13:18:52 76.81 200 3.9 2026-09-15 47 79.26
20 2026-07-29 13:19:52 76.79 200 0.29 2026-09-15 47 81.39
21 2026-07-29 13:20:52 81.92 200 0.38 2026-09-15 47 81.31
22 2026-07-29 13:21:52 79.67 200 0.39 2026-09-15 47 75.22
23 2026-07-29 13:22:53 91.11 200 0.35 2026-09-15 47 77.56
24 2026-07-29 13:23:53 85.6 200 4.12 2026-09-15 47 75.11
25 2026-07-29 13:24:53 79.27 200 0.36 2026-09-15 47 80.63
26 2026-07-29 13:25:53 77.88 200 0.32 2026-09-15 47 82.34
27 2026-07-29 13:26:54 79.35 200 0.49 2026-09-15 47 74.78
28 2026-07-29 13:27:54 96.65 200 0.37 2026-09-15 47 75.99
29 2026-07-29 13:28:54 81.67 200 1.55 2026-09-15 47 72.96
30 2026-07-29 13:29:54 96.08 200 4.82 2026-09-15 47 77.69
31 2026-07-29 13:30:56 931.52 200 0.33 2026-09-15 47 83.28
32 2026-07-29 13:31:56 80.81 200 1.11 2026-09-15 47 79.18
33 2026-07-29 13:32:56 156.07 200 0.5 2026-09-15 47 77.07
34 2026-07-29 13:35:19 84.33 200 1.81 2026-09-15 47 89.93
35 2026-07-29 13:36:20 82.3 200 0.45 2026-09-15 47 76.14
36 2026-07-29 13:37:20 81.27 200 0.38 2026-09-15 47 78.65
37 2026-07-29 13:38:20 176.09 200 0.53 2026-09-15 47 102.99
38 2026-07-29 13:46:29 92.47 200 0.31 2026-09-15 47 73.5
39 2026-07-29 13:47:29 79.73 200 0.32 2026-09-15 47 79.24
40 2026-07-29 13:48:29 76.52 200 0.64 2026-09-15 47 79.0
41 2026-07-29 13:49:29 80.01 200 0.55 2026-09-15 47 78.53
42 2026-07-29 13:50:30 78.15 200 1.62 2026-09-15 47 75.87
43 2026-07-29 13:51:30 135.51 200 0.43 2026-09-15 47 79.1
44 2026-07-29 13:52:30 75.61 200 0.36 2026-09-15 47 77.5
45 2026-07-29 13:53:31 77.33 200 0.38 2026-09-15 47 120.55
46 2026-07-29 13:54:31 77.05 200 0.57 2026-09-15 47 77.96
47 2026-07-29 13:55:31 78.7 200 0.4 2026-09-15 47 72.49
48 2026-07-29 13:56:31 100.53 200 0.36 2026-09-15 47 76.88
49 2026-07-29 13:57:32 82.96 200 0.38 2026-09-15 47 86.56
50 2026-07-29 13:58:32 96.16 200 0.45 2026-09-15 47 74.9
51 2026-07-29 13:59:32 79.9 200 0.32 2026-09-15 47 74.98
52 2026-07-29 14:00:32 80.24 200 1.81 2026-09-15 47 73.09
53 2026-07-29 14:01:33 130.87 200 0.35 2026-09-15 47 76.39

عرض الملف

@@ -0,0 +1,142 @@
import requests
import socket
import ssl
import time
import csv
import os
from datetime import datetime
HOST = "mithal.space"
URL = f"https://{HOST}"
SEARCH_URL = f"{URL}/?q=test"
CSV_FILE = "metrics.csv"
def check_latency():
start = time.time()
response = requests.get(URL, timeout=10)
latency = round((time.time() - start) * 1000, 2)
return latency, response.status_code
def check_dns():
start = time.time()
socket.gethostbyname(HOST)
dns_time = round((time.time() - start) * 1000, 2)
return dns_time
def check_ssl():
context = ssl.create_default_context()
with context.wrap_socket(
socket.socket(),
server_hostname=HOST
) as s:
s.settimeout(10)
s.connect((HOST, 443))
cert = s.getpeercert()
expire = cert["notAfter"]
expire_date = datetime.strptime(
expire,
"%b %d %H:%M:%S %Y %Z"
)
remaining = (expire_date - datetime.utcnow()).days
return expire_date.strftime("%Y-%m-%d"), remaining
def check_search():
start = time.time()
requests.get(SEARCH_URL, timeout=10)
search_latency = round(
(time.time() - start) * 1000,
2
)
return search_latency
def save_csv(data):
file_exists = os.path.isfile(CSV_FILE)
with open(CSV_FILE, "a", newline="") as file:
writer = csv.writer(file)
if not file_exists:
writer.writerow([
"Timestamp",
"Latency(ms)",
"Status",
"DNS(ms)",
"SSL Expiry",
"Days Left",
"Search(ms)"
])
writer.writerow(data)
def monitor():
while True:
try:
latency, status = check_latency()
dns = check_dns()
ssl_date, ssl_days = check_ssl()
search = check_search()
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
row = [
now,
latency,
status,
dns,
ssl_date,
ssl_days,
search
]
save_csv(row)
print(row)
except Exception as e:
print("Monitoring Error:", e)
print("Waiting 60 seconds...\n")
time.sleep(60)
if __name__ == "__main__":
monitor()

عرض الملف

@@ -0,0 +1,59 @@
name: Build, Push and Deploy
on:
push:
branches:
- main
jobs:
build:
name: Build and Push Docker Image
runs-on: self-hosted
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
- name: Build Docker Image
run: |
docker build -t ${{ secrets.DOCKER_USERNAME }}/mithal-monitor:${{ github.sha }} .
- name: Push Docker Image
run: |
docker push ${{ secrets.DOCKER_USERNAME }}/mithal-monitor:${{ github.sha }}
deploy-production:
name: Deploy to Production
needs: build
runs-on: self-hosted
environment:
name: production
steps:
- name: Pull Latest Image
run: |
docker pull ${{ secrets.DOCKER_USERNAME }}/mithal-monitor:${{ github.sha }}
- name: Stop Existing Container
run: |
docker stop mithal-monitor || true
docker rm mithal-monitor || true
- name: Run New Container
run: |
docker run -d \
--name mithal-monitor \
--restart unless-stopped \
-p 8000:8000 \
${{ secrets.DOCKER_USERNAME }}/mithal-monitor:${{ github.sha }}
- name: Verify Deployment
run: |
docker ps

عرض الملف

@@ -0,0 +1,3 @@
requests
pandas
dnspython

121
q5-mithal-monitor/style.css Normal file
عرض الملف

@@ -0,0 +1,121 @@
*{
margin:0;
padding:0;
box-sizing:border-box;
font-family:Arial, Helvetica, sans-serif;
}
body{
background:#f4f7fb;
color:#333;
}
.container{
width:95%;
max-width:1200px;
margin:30px auto;
}
h1{
text-align:center;
margin-bottom:30px;
color:#2c3e50;
}
.cards{
display:flex;
gap:20px;
justify-content:center;
margin-bottom:30px;
flex-wrap:wrap;
}
.card{
background:#fff;
width:280px;
padding:25px;
border-radius:12px;
text-align:center;
box-shadow:0 5px 15px rgba(0,0,0,.08);
}
.card h3{
color:#666;
margin-bottom:15px;
}
.card h2{
color:#2c3e50;
font-size:32px;
}
.chart-container{
background:#fff;
padding:20px;
border-radius:12px;
box-shadow:0 5px 15px rgba(0,0,0,.08);
margin-bottom:30px;
height:450px;
}
.table-container{
background:#fff;
padding:20px;
border-radius:12px;
box-shadow:0 5px 15px rgba(0,0,0,.08);
}
.table-container h2{
margin-bottom:20px;
}
table{
width:100%;
border-collapse:collapse;
}
th{
background:#3498db;
color:white;
padding:12px;
}
td{
padding:12px;
border-bottom:1px solid #ddd;
text-align:center;
}
tr:hover{
background:#f8f8f8;
}
.up{
color:green;
font-weight:bold;
}
.down{
color:red;
font-weight:bold;
}
canvas{
width:100% !important;
height:100% !important;
}
@media(max-width:768px){
.cards{
flex-direction:column;
align-items:center;
}
table{
font-size:14px;
}
.chart-container{
height:350px;
}