ping / app.py
Alvin3y1's picture
Update app.py
706ce69 verified
import threading
import time
import requests
import os
import datetime
from flask import Flask, jsonify, request
from wsgiref.simple_server import make_server
app = Flask(__name__)
# --- CONFIGURATION ---
URL_FILE = 'urls.txt'
SELF_PING_URL = "https://alvin3y1-ping.hf.space/"
INTERVAL_SECONDS = 4 * 3600 # 4 hours
# --- GLOBAL STATE ---
monitoring_state = {}
scan_state = {
'is_scanning': False,
'total': 0,
'completed': 0,
'last_scan_time': 'Never'
}
state_lock = threading.Lock()
# --- FRONTEND TEMPLATE ---
# Served as a static string to keep the project to one file.
HTML_TEMPLATE = """
<!DOCTYPE html>
<html lang="en" class="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Service Status</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-black text-gray-200 min-h-screen p-6 font-sans">
<div class="max-w-2xl mx-auto">
<div class="flex justify-between items-center mb-8 border-b border-gray-800 pb-4">
<h1 class="text-xl font-bold">System Status</h1>
<button onclick="triggerScan()" id="scan-btn" class="bg-gray-800 hover:bg-gray-700 px-3 py-1 text-sm rounded transition">Run Scan</button>
</div>
<div id="progress" class="hidden mb-6">
<div class="w-full bg-gray-800 h-1 rounded-full overflow-hidden">
<div id="bar" class="bg-blue-500 h-full w-0 transition-all duration-300"></div>
</div>
</div>
<div id="alerts" class="space-y-3"></div>
</div>
<script>
async function fetchStatus() {
const res = await fetch('/api/status');
const data = await res.json();
// Handle Progress
const prog = document.getElementById('progress');
if (data.scan.is_scanning) {
prog.classList.remove('hidden');
const percent = (data.scan.completed / data.scan.total) * 100;
document.getElementById('bar').style.width = percent + '%';
} else {
prog.classList.add('hidden');
}
// Handle Down URLs
const container = document.getElementById('alerts');
container.innerHTML = data.down_urls.length ? '' : '<p class="text-green-500 text-center py-10">All Systems Operational</p>';
data.down_urls.forEach(u => {
container.innerHTML += `
<div class="bg-red-950/20 border border-red-900/50 p-4 rounded flex justify-between items-center">
<div>
<div class="text-sm font-mono text-red-200">${u.url}</div>
<div class="text-xs text-red-500 mt-1">${u.msg} (${u.code})</div>
</div>
<button onclick="retry('${u.url}')" class="text-xs bg-red-900 px-2 py-1 rounded">Retry</button>
</div>`;
});
}
async function triggerScan() {
await fetch('/api/scan', {method: 'POST'});
fetchStatus();
}
async function retry(url) {
await fetch('/api/retry', {method: 'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({url})});
fetchStatus();
}
setInterval(fetchStatus, 2000);
fetchStatus();
</script>
</body>
</html>
"""
# --- LOGIC ---
def get_all_urls():
urls = [SELF_PING_URL]
if os.path.exists(URL_FILE):
with open(URL_FILE, 'r') as f:
urls.extend([l.strip() for l in f if l.strip()])
return list(set(urls))
def check_single_url(url):
timestamp = datetime.datetime.now().strftime("%H:%M:%S")
try:
r = requests.get(url, timeout=10)
res = {'status': 'UP' if r.status_code < 400 else 'DOWN', 'code': r.status_code, 'time': timestamp, 'msg': 'OK' if r.status_code < 400 else 'Error'}
except Exception as e:
res = {'status': 'DOWN', 'code': 'ERR', 'time': timestamp, 'msg': str(e)[:20]}
with state_lock:
monitoring_state[url] = res
def perform_full_scan():
urls = get_all_urls()
with state_lock:
scan_state.update({'is_scanning': True, 'total': len(urls), 'completed': 0})
for url in urls:
check_single_url(url)
with state_lock:
scan_state['completed'] += 1
with state_lock:
scan_state.update({'is_scanning': False, 'last_scan_time': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")})
def background_worker():
while True:
perform_full_scan()
time.sleep(INTERVAL_SECONDS)
# --- ROUTES ---
@app.route('/')
def home(): return HTML_TEMPLATE
@app.route('/api/status')
def get_status():
with state_lock:
down = [{'url': u, **s} for u, s in monitoring_state.items() if s['status'] == 'DOWN']
return jsonify({'scan': scan_state, 'down_urls': down})
@app.route('/api/scan', methods=['POST'])
def scan():
threading.Thread(target=perform_full_scan, daemon=True).start()
return jsonify({"status": "started"})
@app.route('/api/retry', methods=['POST'])
def retry():
threading.Thread(target=check_single_url, args=(request.json['url'],), daemon=True).start()
return jsonify({"status": "retrying"})
if __name__ == '__main__':
threading.Thread(target=background_worker, daemon=True).start()
print("Server starting on http://0.0.0.0:7860")
make_server('0.0.0.0', 7860, app).serve_forever()