Restructure repository for final submission
فشلت بعض الفحوصات
CI/CD - Build & Deploy to Ghaymah Cloud / build-and-test (push) Has been cancelled
CI/CD - Build & Deploy to Ghaymah Cloud / deploy-staging (push) Has been cancelled
CI/CD - Build & Deploy to Ghaymah Cloud / deploy-production (push) Has been cancelled

هذا الالتزام موجود في:
Ubuntu
2026-07-28 13:22:05 +00:00
الأصل b43f9bf706
التزام 54af9f97ac
27 ملفات معدلة مع 1939 إضافات و0 حذوفات

عرض الملف

@@ -0,0 +1,72 @@
# Integration Proposal - Product 1: Green Framework
## 1. Selected Product Description
- **Product Name:** Green Framework
- **Overview:** A modern PHP framework designed for building web applications and REST APIs efficiently. It helps developers create scalable backend applications with a clean and organized structure.
---
## 2. How it integrates with `ghaymah.systems`
### Proposed Integration
1. Developers can deploy Green Framework applications on Ghaymah cloud infrastructure.
2. Source code can be connected to a CI/CD pipeline to automate building and deployment.
3. Docker containers can be used to package the application for consistent deployments.
4. Monitoring and logging tools can be connected to monitor application health and performance.
---
## 3. Added Value for the End User
- Faster application deployment.
- Easier application maintenance.
- More reliable hosting environment.
- Better visibility into application health and availability.
- Simplified deployment workflow for development teams.
---
## 4. Architecture Sketch
```text
Developer
Git Repository
CI/CD Pipeline
Docker Container
Ghaymah Infrastructure
Green Framework Application
Monitoring & Logs
```
---
## 5. Potential Technical or Commercial Challenges
### Technical
- Managing environment variables securely.
- Handling database migrations during deployments.
- Monitoring application performance across environments.
### Commercial
- Encouraging developers to adopt a new hosting platform.
- Providing clear migration guides for existing applications.
---
## 6. Which product is more viable?
**Green Framework** is the stronger integration candidate because every application built with the framework eventually needs a reliable deployment environment. Integrating it with Ghaymah would provide developers with a complete deployment workflow while supporting modern DevOps practices.

عرض الملف

@@ -0,0 +1,67 @@
# Integration Proposal - Product 2: Jadel (جَدَل)
## 1. Selected Product Description
- **Product Name:** Jadel
- **Overview:** A SaaS platform for managing fitness centers and gyms, including memberships, subscriptions, attendance, and daily business operations.
---
## 2. How it integrates with `ghaymah.systems`
### Proposed Integration
1. Host the Jadel platform on Ghaymah infrastructure to improve service availability.
2. Run the application and its database in a secure cloud environment.
3. Connect monitoring tools to observe application health and detect failures.
4. Schedule regular backups to reduce the risk of data loss.
---
## 3. Added Value for the End User
- Higher application availability.
- Improved system reliability.
- Better monitoring for administrators.
- Easier infrastructure management.
- Ability to support business growth without major infrastructure changes.
---
## 4. Architecture Sketch
```text
Gym Staff
Jadel Platform
Ghaymah Infrastructure
┌───┴──────────┐
▼ ▼
Application Database
Monitoring & Backups
```
---
## 5. Potential Technical or Commercial Challenges
### Technical
- Protecting customer information.
- Database migration and backup management.
- Maintaining service availability during updates.
### Commercial
- Convincing businesses to migrate from existing systems.
- Training users on the new platform.
---
## 6. Which product is more viable?
Although Jadel would benefit from cloud hosting, its adoption depends mainly on business demand within the fitness industry. Compared to Green Framework, it targets a more specific market, making its integration slightly less flexible.

عرض الملف

@@ -0,0 +1,4 @@
Name: Mohammed Hamdy Mahmoud
Qabilah Profile:
https://qabilah.com/profile/mohammedhamdy102003/posts

عرض الملف

179
q1-deploy-monitor/README.md Normal file
عرض الملف

@@ -0,0 +1,179 @@
# Q1 - Deploy and Monitor an API on Ghaymah Cloud
## Overview
This project demonstrates deploying a Dockerized Python API to **Ghaymah Cloud** and implementing a simple monitoring solution.
The application exposes a `/health` endpoint that is continuously monitored using a Python script. A lightweight HTML dashboard displays the application's health status, response time, uptime, and request statistics.
---
# Project Structure
```
Q1-Deploy-and-Monitoring/
├── screenshots/
│ ├── dashboard-local.png
│ └── dashboard-ghaymah.png
├── Dockerfile
├── app.py
├── health-check.py
├── dashboard.html
├── monitor-log.csv
├── requirements.txt
├── install-docker.sh
└── README.md
```
---
# Task Requirements
This implementation satisfies all requirements of Question 1.
| Requirement | Status |
|------------|--------|
| Dockerize the API | ✅ |
| Deploy to Ghaymah Cloud | ✅ |
| Implement `/health` endpoint | ✅ |
| Monitoring script (every 30 seconds) | ✅ |
| Monitoring Dashboard | ✅ |
---
# Technologies
- Python
- Flask
- Docker
- HTML
- CSS
- JavaScript
- Ghaymah Cloud
- Ghaymah CLI
---
# API
## Health Endpoint
```
GET /health
```
Example response
```json
{
"status": "healthy"
}
```
The monitoring script periodically sends requests to this endpoint to verify application availability.
---
# Docker
Build the Docker image
```bash
docker build -t exam-api .
```
Run the container
```bash
docker run -d -p 5000:5000 exam-api
```
---
# Monitoring Script
The monitoring script (`health-check.py`) executes every **30 seconds** and performs the following operations:
- Sends an HTTP request to `/health`
- Measures response latency
- Detects application availability
- Records monitoring results
- Updates `monitor-log.csv`
Run the monitor
```bash
python3 health-check.py
```
---
# Monitoring Dashboard
The dashboard was implemented using HTML, CSS and JavaScript.
Displayed metrics include:
- Current application status
- Response time
- Total requests
- Application uptime
- Monitoring history
---
# Deployment using Ghaymah CLI
The application was deployed to **Ghaymah Cloud** using the official CLI.
Deployment workflow:
1. Install Ghaymah CLI
2. Authenticate using account credentials
3. Select deployment configuration
4. Launch the application
Example commands
```bash
gy auth login
cp .ghaymah.production.json .ghaymah.json
gy resource app launch
```
---
# Dashboard Preview
## Local Testing
The dashboard was first tested locally against the application running on the EC2 instance before deploying to Ghaymah Cloud.
![Local Dashboard](screenshots/dashboard-local.png)
---
## Ghaymah Cloud Deployment
After deployment, the dashboard successfully monitored the live application hosted on **Ghaymah Cloud**.
![Ghaymah Dashboard](screenshots/dashboard-ghaymah.png)
---
# Result
The project successfully demonstrates:
- Docker containerization
- Cloud deployment on Ghaymah
- Automated health monitoring
- Response time tracking
- Monitoring dashboard
- Continuous application health verification
This implementation satisfies all requirements of **Question 1 Deploy and Monitor an API on Ghaymah Cloud**.

عرض الملف

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 135 KiB

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 134 KiB

191
q3-cicd/README.md Normal file
عرض الملف

@@ -0,0 +1,191 @@
# Q3 CI/CD Pipeline on Ghaymah Cloud
## Overview
This task implements a complete CI/CD pipeline using **GitHub Actions** and **Ghaymah Cloud**.
The pipeline automatically builds the application, performs a smoke test, deploys to the **staging** environment for development changes, and deploys to the **production** environment after merging into the `main` branch with **manual approval** enabled.
---
# Pipeline Workflow
```
Developer
│ Push
GitHub Repository
GitHub Actions
├── Build Docker Image
├── Smoke Test (/health)
├──────────────┐
│ │
▼ ▼
develop main
│ │
Deploy Manual Approval
Staging │
Deploy Production
```
---
# CI Pipeline
The Continuous Integration stage performs:
- Checkout repository
- Build Docker image
- Start container
- Execute smoke test
- Verify `/health` endpoint
- Stop and remove the test container
This ensures that only healthy builds continue to deployment.
---
# CD Pipeline
## Staging Deployment
Triggered automatically when code is pushed to the **develop** branch.
Steps:
1. Install Ghaymah CLI
2. Authenticate using GitHub Secrets
3. Load `.ghaymah.staging.json`
4. Deploy application to the staging environment
Purpose:
- Integration testing
- Validation before production
- Detect deployment issues early
---
## Production Deployment
Triggered after merging into the **main** branch.
Deployment requires **manual approval** through the GitHub Environment protection rules before execution.
Steps:
1. Install Ghaymah CLI
2. Authenticate using GitHub Secrets
3. Load `.ghaymah.production.json`
4. Deploy application to the production environment
Purpose:
- Stable release
- Manual verification before deployment
- Reduce production risks
---
# Staging vs Production
| Staging | Production |
|----------|------------|
| Testing environment | Live environment |
| Used by developers | Used by end users |
| Automatic deployment | Protected deployment |
| Safe for validation | High availability |
| Can be updated frequently | Only verified releases |
---
# Manual Approval
Production deployments are protected using **GitHub Environments**.
The workflow pauses before deploying to production until manual approval is granted.
Benefits:
- Prevent accidental deployments
- Final verification before release
- Safer production deployments
---
# Ghaymah CLI Integration
Deployment is performed using the official **Ghaymah CLI**.
Installation:
```bash
curl -sSL https://cli.ghaymah.systems/install.sh | bash
```
Authentication:
```bash
gy auth login \
--email "<EMAIL>" \
--password "<PASSWORD>"
```
Deployment:
```bash
cp .ghaymah.production.json .ghaymah.json
gy resource app launch
```
For the staging environment, the workflow uses:
```bash
cp .ghaymah.staging.json .ghaymah.json
```
before deployment.
---
# GitHub Secrets
Sensitive credentials are stored securely as GitHub Secrets.
Secrets used:
- GHAYMAH_EMAIL
- GHAYMAH_PW
No credentials are stored inside the repository.
---
# Technologies Used
- GitHub Actions
- Docker
- Ghaymah Cloud
- Ghaymah CLI
- GitHub Environments
- GitHub Secrets
---
# Result
The pipeline successfully performs:
- Automated Docker image build
- Smoke testing
- Automatic deployment to Staging
- Manual approval before Production
- Production deployment using Ghaymah CLI
This implementation provides a reliable and production-ready CI/CD workflow.

عرض الملف

قبل

العرض:  |  الارتفاع:  |  الحجم: 1.2 MiB

بعد

العرض:  |  الارتفاع:  |  الحجم: 1.2 MiB

عرض الملف

@@ -0,0 +1,6 @@
.venv
__pycache__
*.pyc
.git
monitor-data.json
README.md

عرض الملف

@@ -0,0 +1,17 @@
{
"id": "bbf0b1b5-2214-479e-b5e7-00be81bd0e7d",
"name": "mithal-monitor",
"projectId": "6d1bb957-8a2c-4a88-86f3-6a937b7971f0",
"ports": [
{
"expose": true,
"number": 5000
}
],
"publicAccess": {
"enabled": true,
"domain": "auto"
},
"resourceTier": "t1",
"dockerFileName": "Dockerfile"
}

عرض الملف

@@ -0,0 +1,13 @@
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]

161
q5-mithal-monitor/README.md Normal file
عرض الملف

@@ -0,0 +1,161 @@
# Mithal Monitor
A Flask-based monitoring application that periodically collects website metrics and exposes them through REST APIs. The application is containerized with Docker and deployed on Ghaymah.
## Features
- Monitor website availability
- Measure DNS lookup time
- Measure HTTP latency
- Measure search latency
- Check SSL certificate expiration
- Store collected metrics
- REST API for health checks and metrics
- Dockerized deployment
- Deployed on Ghaymah
---
## Tech Stack
- Python
- Flask
- SQLite
- Docker
- Gunicorn
- Ghaymah
---
## API Endpoints
### Health Check
```http
GET /health
```
Example Response
```json
{
"status": "healthy"
}
```
---
### Metrics
```http
GET /api/metrics
```
Example Response
```json
[
{
"timestamp": "2026-07-28 12:11:50",
"uptime": true,
"status_code": 200,
"latency_ms": 34.03,
"dns_ms": 2.38,
"search_latency_ms": 108.42,
"ssl_days_left": 49,
"ssl_expiry": "2026-09-15"
}
]
```
---
## Running Locally
Clone the repository
```bash
git clone <repo-url>
cd Q5-Mithal-Monitor
```
Install dependencies
```bash
pip install -r requirements.txt
```
Run the application
```bash
python app.py
```
The application will be available on
```
http://localhost:5000
```
---
## Docker
Build the image
```bash
docker build -t mithal-monitor .
```
Run the container
```bash
docker run -p 80:80 mithal-monitor
```
---
## Deployment
The application is deployed on Ghaymah.
Deployment URL:
```
https://mithal-monitor-74639f9fbe38.hosted.ghaymah.systems
```
Health Endpoint
```
https://mithal-monitor-74639f9fbe38.hosted.ghaymah.systems/health
```
Metrics Endpoint
```
https://mithal-monitor-74639f9fbe38.hosted.ghaymah.systems/api/metrics
```
---
## Project Structure
```
Q5-Mithal-Monitor/
├── app.py
├── requirements.txt
├── Dockerfile
├── monitor.db
├── templates/
├── static/
├── .ghaymah.json
└── README.md
```
---
## Author
Mohammed Hamdy

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

@@ -0,0 +1,66 @@
from flask import Flask, jsonify, render_template
import json
import os
import threading
import time
import monitor # our monitor.py — reused directly, not run as a separate process
app = Flask(__name__)
DATA_FILE = "monitor-data.json"
def background_monitor_loop():
"""Runs monitor.monitor() every CHECK_INTERVAL seconds inside this
same process/container, since the Dockerfile only starts one
process (gunicorn running app.py). This replaces running
monitor.py as a separate process, which never actually happened
after deployment (only app.py ran, monitor.py was never invoked)."""
print("Starting background monitor thread...")
while True:
try:
monitor.monitor()
except Exception as e:
print("Monitor thread error:", e)
time.sleep(monitor.CHECK_INTERVAL)
# Start the background thread once, when this module is imported by
# gunicorn. Safe because the Dockerfile runs a single gunicorn worker
# (no --workers flag => defaults to 1), so this thread won't be
# duplicated across multiple worker processes.
monitor_thread = threading.Thread(target=background_monitor_loop, daemon=True)
monitor_thread.start()
@app.route("/")
def home():
return render_template("dashboard.html")
@app.route("/dashboard")
def dashboard():
return render_template("dashboard.html")
@app.route("/api/metrics")
def metrics():
if not os.path.exists(DATA_FILE):
return jsonify([])
with open(DATA_FILE, "r") as f:
data = json.load(f)
return jsonify(data)
@app.route("/health")
def health():
return {
"status": "healthy"
}
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True)

عرض الملف

@@ -0,0 +1,692 @@
[
{
"timestamp": "2026-07-28 06:15:26",
"uptime": true,
"status_code": 200,
"latency_ms": 138.66,
"dns_ms": 1.88,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 83.64
},
{
"timestamp": "2026-07-28 06:16:27",
"uptime": true,
"status_code": 200,
"latency_ms": 77.9,
"dns_ms": 1.0,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 76.89
},
{
"timestamp": "2026-07-28 06:17:27",
"uptime": true,
"status_code": 200,
"latency_ms": 76.17,
"dns_ms": 0.99,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 90.49
},
{
"timestamp": "2026-07-28 06:18:27",
"uptime": true,
"status_code": 200,
"latency_ms": 83.58,
"dns_ms": 1.11,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 75.83
},
{
"timestamp": "2026-07-28 06:19:27",
"uptime": true,
"status_code": 200,
"latency_ms": 78.07,
"dns_ms": 0.82,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 83.3
},
{
"timestamp": "2026-07-28 06:20:27",
"uptime": true,
"status_code": 200,
"latency_ms": 96.93,
"dns_ms": 1.13,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 78.55
},
{
"timestamp": "2026-07-28 06:21:28",
"uptime": true,
"status_code": 200,
"latency_ms": 78.4,
"dns_ms": 1.37,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 76.19
},
{
"timestamp": "2026-07-28 06:22:28",
"uptime": true,
"status_code": 200,
"latency_ms": 88.03,
"dns_ms": 0.89,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 79.74
},
{
"timestamp": "2026-07-28 06:23:28",
"uptime": true,
"status_code": 200,
"latency_ms": 77.57,
"dns_ms": 1.22,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 76.56
},
{
"timestamp": "2026-07-28 06:24:28",
"uptime": true,
"status_code": 200,
"latency_ms": 75.44,
"dns_ms": 0.98,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 83.31
},
{
"timestamp": "2026-07-28 06:25:28",
"uptime": true,
"status_code": 200,
"latency_ms": 80.72,
"dns_ms": 0.9,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 74.22
},
{
"timestamp": "2026-07-28 06:26:29",
"uptime": true,
"status_code": 200,
"latency_ms": 81.2,
"dns_ms": 0.87,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 77.07
},
{
"timestamp": "2026-07-28 06:27:29",
"uptime": true,
"status_code": 200,
"latency_ms": 76.89,
"dns_ms": 1.5,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 74.69
},
{
"timestamp": "2026-07-28 06:28:29",
"uptime": true,
"status_code": 200,
"latency_ms": 78.55,
"dns_ms": 0.84,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 91.66
},
{
"timestamp": "2026-07-28 06:29:29",
"uptime": true,
"status_code": 200,
"latency_ms": 82.33,
"dns_ms": 1.07,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 75.03
},
{
"timestamp": "2026-07-28 06:30:30",
"uptime": true,
"status_code": 200,
"latency_ms": 91.92,
"dns_ms": 0.87,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 76.92
},
{
"timestamp": "2026-07-28 06:31:30",
"uptime": true,
"status_code": 200,
"latency_ms": 80.75,
"dns_ms": 0.9,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 76.38
},
{
"timestamp": "2026-07-28 06:32:30",
"uptime": true,
"status_code": 200,
"latency_ms": 79.62,
"dns_ms": 0.86,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 74.62
},
{
"timestamp": "2026-07-28 06:33:30",
"uptime": true,
"status_code": 200,
"latency_ms": 75.97,
"dns_ms": 0.82,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 82.48
},
{
"timestamp": "2026-07-28 06:34:30",
"uptime": true,
"status_code": 200,
"latency_ms": 79.56,
"dns_ms": 0.88,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 73.19
},
{
"timestamp": "2026-07-28 06:35:31",
"uptime": true,
"status_code": 200,
"latency_ms": 98.91,
"dns_ms": 0.86,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 82.02
},
{
"timestamp": "2026-07-28 06:36:31",
"uptime": true,
"status_code": 200,
"latency_ms": 74.78,
"dns_ms": 0.92,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 72.29
},
{
"timestamp": "2026-07-28 06:37:31",
"uptime": true,
"status_code": 200,
"latency_ms": 77.6,
"dns_ms": 0.89,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 74.45
},
{
"timestamp": "2026-07-28 06:38:31",
"uptime": true,
"status_code": 200,
"latency_ms": 78.87,
"dns_ms": 1.08,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 76.15
},
{
"timestamp": "2026-07-28 06:39:31",
"uptime": true,
"status_code": 200,
"latency_ms": 80.61,
"dns_ms": 1.34,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 72.64
},
{
"timestamp": "2026-07-28 06:40:32",
"uptime": true,
"status_code": 200,
"latency_ms": 80.76,
"dns_ms": 0.85,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 78.7
},
{
"timestamp": "2026-07-28 06:41:32",
"uptime": true,
"status_code": 200,
"latency_ms": 85.68,
"dns_ms": 0.83,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 80.57
},
{
"timestamp": "2026-07-28 06:42:39",
"uptime": true,
"status_code": 200,
"latency_ms": 6717.43,
"dns_ms": 0.87,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 83.14
},
{
"timestamp": "2026-07-28 06:43:39",
"uptime": true,
"status_code": 200,
"latency_ms": 76.05,
"dns_ms": 0.82,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 75.75
},
{
"timestamp": "2026-07-28 06:44:39",
"uptime": true,
"status_code": 200,
"latency_ms": 78.1,
"dns_ms": 0.8,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 85.88
},
{
"timestamp": "2026-07-28 06:45:39",
"uptime": true,
"status_code": 200,
"latency_ms": 112.41,
"dns_ms": 0.88,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 81.98
},
{
"timestamp": "2026-07-28 06:46:40",
"uptime": true,
"status_code": 200,
"latency_ms": 77.23,
"dns_ms": 0.92,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 73.45
},
{
"timestamp": "2026-07-28 06:47:40",
"uptime": true,
"status_code": 200,
"latency_ms": 79.96,
"dns_ms": 0.85,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 73.76
},
{
"timestamp": "2026-07-28 06:48:40",
"uptime": true,
"status_code": 200,
"latency_ms": 82.81,
"dns_ms": 0.88,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 73.3
},
{
"timestamp": "2026-07-28 06:49:40",
"uptime": true,
"status_code": 200,
"latency_ms": 83.33,
"dns_ms": 0.87,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 72.03
},
{
"timestamp": "2026-07-28 06:50:40",
"uptime": true,
"status_code": 200,
"latency_ms": 81.64,
"dns_ms": 0.85,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 73.87
},
{
"timestamp": "2026-07-28 06:51:41",
"uptime": true,
"status_code": 200,
"latency_ms": 87.24,
"dns_ms": 0.83,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 79.31
},
{
"timestamp": "2026-07-28 06:52:41",
"uptime": true,
"status_code": 200,
"latency_ms": 80.97,
"dns_ms": 1.19,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 77.43
},
{
"timestamp": "2026-07-28 06:53:41",
"uptime": true,
"status_code": 200,
"latency_ms": 81.17,
"dns_ms": 0.98,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 73.72
},
{
"timestamp": "2026-07-28 06:54:41",
"uptime": true,
"status_code": 200,
"latency_ms": 82.47,
"dns_ms": 0.86,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 75.56
},
{
"timestamp": "2026-07-28 06:55:41",
"uptime": true,
"status_code": 200,
"latency_ms": 80.53,
"dns_ms": 0.98,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 80.2
},
{
"timestamp": "2026-07-28 06:56:42",
"uptime": true,
"status_code": 200,
"latency_ms": 83.64,
"dns_ms": 0.82,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 71.71
},
{
"timestamp": "2026-07-28 06:57:42",
"uptime": true,
"status_code": 200,
"latency_ms": 81.55,
"dns_ms": 0.84,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 72.56
},
{
"timestamp": "2026-07-28 06:58:42",
"uptime": true,
"status_code": 200,
"latency_ms": 82.6,
"dns_ms": 0.88,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 78.6
},
{
"timestamp": "2026-07-28 06:59:42",
"uptime": true,
"status_code": 200,
"latency_ms": 79.31,
"dns_ms": 0.86,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 74.71
},
{
"timestamp": "2026-07-28 07:00:43",
"uptime": true,
"status_code": 200,
"latency_ms": 99.38,
"dns_ms": 0.88,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 73.06
},
{
"timestamp": "2026-07-28 07:01:43",
"uptime": true,
"status_code": 200,
"latency_ms": 78.82,
"dns_ms": 0.86,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 79.59
},
{
"timestamp": "2026-07-28 07:02:43",
"uptime": true,
"status_code": 200,
"latency_ms": 97.32,
"dns_ms": 1.02,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 85.14
},
{
"timestamp": "2026-07-28 07:03:43",
"uptime": true,
"status_code": 200,
"latency_ms": 97.17,
"dns_ms": 0.88,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 75.99
},
{
"timestamp": "2026-07-28 07:04:43",
"uptime": true,
"status_code": 200,
"latency_ms": 77.36,
"dns_ms": 0.94,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 75.38
},
{
"timestamp": "2026-07-28 07:05:44",
"uptime": true,
"status_code": 200,
"latency_ms": 126.34,
"dns_ms": 0.94,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 78.33
},
{
"timestamp": "2026-07-28 07:06:44",
"uptime": true,
"status_code": 200,
"latency_ms": 78.6,
"dns_ms": 0.83,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 77.94
},
{
"timestamp": "2026-07-28 07:07:44",
"uptime": true,
"status_code": 200,
"latency_ms": 80.89,
"dns_ms": 0.84,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 74.3
},
{
"timestamp": "2026-07-28 07:08:44",
"uptime": true,
"status_code": 200,
"latency_ms": 77.8,
"dns_ms": 1.0,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 79.14
},
{
"timestamp": "2026-07-28 07:09:45",
"uptime": true,
"status_code": 200,
"latency_ms": 83.49,
"dns_ms": 0.86,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 75.71
},
{
"timestamp": "2026-07-28 07:10:45",
"uptime": true,
"status_code": 200,
"latency_ms": 72.7,
"dns_ms": 0.86,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 80.3
},
{
"timestamp": "2026-07-28 07:11:45",
"uptime": true,
"status_code": 200,
"latency_ms": 79.11,
"dns_ms": 0.86,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 79.6
},
{
"timestamp": "2026-07-28 07:12:45",
"uptime": true,
"status_code": 200,
"latency_ms": 80.55,
"dns_ms": 0.88,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 76.45
},
{
"timestamp": "2026-07-28 07:13:45",
"uptime": true,
"status_code": 200,
"latency_ms": 80.62,
"dns_ms": 0.85,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 76.94
},
{
"timestamp": "2026-07-28 07:14:46",
"uptime": true,
"status_code": 200,
"latency_ms": 82.55,
"dns_ms": 0.85,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 74.5
},
{
"timestamp": "2026-07-28 07:15:47",
"uptime": true,
"status_code": 200,
"latency_ms": 986.76,
"dns_ms": 0.86,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 84.61
},
{
"timestamp": "2026-07-28 07:16:47",
"uptime": true,
"status_code": 200,
"latency_ms": 103.86,
"dns_ms": 0.98,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 100.18
},
{
"timestamp": "2026-07-28 07:17:48",
"uptime": true,
"status_code": 200,
"latency_ms": 910.26,
"dns_ms": 0.88,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 81.43
},
{
"timestamp": "2026-07-28 07:18:49",
"uptime": true,
"status_code": 200,
"latency_ms": 910.72,
"dns_ms": 0.89,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 83.03
},
{
"timestamp": "2026-07-28 07:19:49",
"uptime": true,
"status_code": 200,
"latency_ms": 76.95,
"dns_ms": 0.86,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 74.19
},
{
"timestamp": "2026-07-28 07:20:50",
"uptime": true,
"status_code": 200,
"latency_ms": 93.67,
"dns_ms": 1.39,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 75.06
},
{
"timestamp": "2026-07-28 07:21:50",
"uptime": true,
"status_code": 200,
"latency_ms": 83.26,
"dns_ms": 0.87,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 74.3
},
{
"timestamp": "2026-07-28 07:22:50",
"uptime": true,
"status_code": 200,
"latency_ms": 83.7,
"dns_ms": 0.84,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 77.12
},
{
"timestamp": "2026-07-28 07:23:50",
"uptime": true,
"status_code": 200,
"latency_ms": 76.43,
"dns_ms": 0.87,
"ssl_expiry": "2026-09-15",
"ssl_days_left": 49,
"search_latency_ms": 75.44
}
]

عرض الملف

@@ -0,0 +1,187 @@
import requests
import socket
import ssl
import json
import os
import time
import dns.resolver
from datetime import datetime, UTC
# ===========================================
# Configuration
# ===========================================
BASE_URL = "https://mithal.space"
SEARCH_URL = "https://mithal.space/search?q=cloud"
OUTPUT_FILE = "monitor-data.json"
CHECK_INTERVAL = 60
# ===========================================
# HTTP Latency + Uptime
# ===========================================
def check_http():
start = time.perf_counter()
response = requests.get(BASE_URL, timeout=10)
latency = (time.perf_counter() - start) * 1000
return response.status_code, round(latency, 2)
# ===========================================
# Search Response
# ===========================================
def check_search():
start = time.perf_counter()
response = requests.get(SEARCH_URL, timeout=10)
latency = (time.perf_counter() - start) * 1000
return round(latency, 2)
# ===========================================
# DNS Lookup Time
# ===========================================
def check_dns():
resolver = dns.resolver.Resolver()
start = time.perf_counter()
resolver.resolve("mithal.space")
latency = (time.perf_counter() - start) * 1000
return round(latency, 2)
# ===========================================
# SSL Certificate
# ===========================================
def check_ssl():
hostname = "mithal.space"
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 = datetime.strptime(
cert["notAfter"],
"%b %d %H:%M:%S %Y %Z"
).replace(tzinfo=UTC)
days_left = (expiry - datetime.now(UTC)).days
return expiry.strftime("%Y-%m-%d"), days_left
# ===========================================
# JSON
# ===========================================
def load_history():
if not os.path.exists(OUTPUT_FILE):
return []
try:
with open(OUTPUT_FILE, "r") as f:
content = f.read().strip()
if not content:
return []
return json.loads(content)
except (json.JSONDecodeError, FileNotFoundError):
return []
def save_history(data):
with open(OUTPUT_FILE, "w") as f:
json.dump(data, f, indent=4)
# ===========================================
# Monitoring
# ===========================================
def monitor():
status_code, latency = check_http()
ssl_expiry, ssl_days = check_ssl()
entry = {
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"uptime": status_code == 200,
"status_code": status_code,
"latency_ms": latency,
"dns_ms": check_dns(),
"ssl_expiry": ssl_expiry,
"ssl_days_left": ssl_days,
"search_latency_ms": check_search()
}
history = load_history()
history.append(entry)
# آخر 24 ساعة (كل دقيقة)
history = history[-1440:]
save_history(history)
print("=" * 60)
print(json.dumps(entry, indent=4))
# ===========================================
# Main Loop
# ===========================================
if __name__ == "__main__":
print("Starting Mithal Monitoring...")
while True:
try:
monitor()
except Exception as e:
print("ERROR:", e)
time.sleep(CHECK_INTERVAL)

عرض الملف

@@ -0,0 +1,4 @@
Flask==3.1.1
requests==2.32.4
dnspython==2.7.0
gunicorn==23.0.0

عرض الملف

@@ -0,0 +1,280 @@
<!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>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
*{
margin:0;
padding:0;
box-sizing:border-box;
font-family:Arial,Helvetica,sans-serif;
}
body{
background:#0f172a;
color:white;
padding:30px;
}
.container{
max-width:1400px;
margin:auto;
}
h1{
text-align:center;
margin-bottom:30px;
}
.grid{
display:grid;
grid-template-columns:repeat(auto-fit,minmax(220px,1fr));
gap:20px;
margin-bottom:25px;
}
.card{
background:#1e293b;
border-radius:12px;
padding:20px;
box-shadow:0 0 10px rgba(0,0,0,.3);
}
.card h3{
color:#94a3b8;
margin-bottom:15px;
}
.value{
font-size:32px;
font-weight:bold;
}
.green{
color:#22c55e;
}
.red{
color:#ef4444;
}
.orange{
color:#f59e0b;
}
.chart{
background:#1e293b;
padding:20px;
border-radius:12px;
margin-bottom:25px;
}
.table-card{
background:#1e293b;
border-radius:12px;
padding:20px;
}
table{
width:100%;
border-collapse:collapse;
}
th{
background:#334155;
padding:12px;
}
td{
text-align:center;
padding:10px;
border-bottom:1px solid #334155;
}
footer{
text-align:center;
margin-top:25px;
color:#94a3b8;
}
</style>
</head>
<body>
<div class="container">
<h1>🚀 Mithal.space Monitoring Dashboard</h1>
<div class="grid">
<div class="card">
<h3>Status</h3>
<div id="status" class="value green">Loading...</div>
</div>
<div class="card">
<h3>HTTP Latency</h3>
<div id="latency" class="value">--</div>
</div>
<div class="card">
<h3>DNS Lookup</h3>
<div id="dns" class="value">--</div>
</div>
<div class="card">
<h3>Search Response</h3>
<div id="search" class="value">--</div>
</div>
<div class="card">
<h3>SSL Days Left</h3>
<div id="ssl" class="value">--</div>
</div>
<div class="card">
<h3>24h Uptime</h3>
<div id="uptime" class="value">--</div>
</div>
</div>
<div class="chart">
<canvas id="latencyChart"></canvas>
</div>
<div class="table-card">
<h2 style="margin-bottom:20px;">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>
<footer>Updates every 60 seconds</footer>
</div>
<script>
let chart;
async function loadData(){
const response = await fetch("/api/metrics");
const data = await response.json();
if(data.length === 0){
return;
}
const latest = data[data.length - 1];
document.getElementById("status").innerHTML =
latest.uptime
? '<span class="green">● ONLINE</span>'
: '<span class="red">● OFFLINE</span>';
document.getElementById("latency").innerHTML = latest.latency_ms + " ms";
document.getElementById("dns").innerHTML = latest.dns_ms + " ms";
document.getElementById("search").innerHTML = latest.search_latency_ms + " ms";
document.getElementById("ssl").innerHTML = latest.ssl_days_left + " days";
const uptimePercent = (
data.filter(x => x.uptime).length / data.length * 100
).toFixed(2);
document.getElementById("uptime").innerHTML = uptimePercent + "%";
const labels = data.slice(-60).map(x => x.timestamp.split(" ")[1]);
const latency = data.slice(-60).map(x => x.latency_ms);
if(chart){
chart.destroy();
}
chart = new Chart(
document.getElementById("latencyChart"),
{
type: "line",
data: {
labels: labels,
datasets: [{
label: "Latency (ms)",
data: latency,
borderWidth: 3,
fill: false,
tension: .3,
borderColor: "#38bdf8"
}]
},
options: {
responsive: true,
plugins: {
legend: {
labels: {
color: "white"
}
}
},
scales: {
x: {
ticks: {
color: "white"
}
},
y: {
ticks: {
color: "white"
}
}
}
}
}
);
const tbody = document.getElementById("history");
tbody.innerHTML = "";
data.slice(-10).reverse().forEach(row => {
tbody.innerHTML += `
<tr>
<td>${row.timestamp}</td>
<td>
${row.uptime
? '<span class="green">Online</span>'
: '<span class="red">Offline</span>'}
</td>
<td>${row.latency_ms} ms</td>
<td>${row.dns_ms} ms</td>
<td>${row.search_latency_ms} ms</td>
<td>${row.ssl_days_left} days</td>
</tr>
`;
});
}
loadData();
setInterval(loadData, 60000);
</script>
</body>
</html>