File size: 5,565 Bytes
1855912
 
 
 
 
706ce69
 
1855912
 
 
 
 
 
706ce69
1855912
 
 
14e0dfb
 
 
 
706ce69
14e0dfb
1855912
 
706ce69
 
1855912
 
14e0dfb
1855912
 
 
706ce69
14e0dfb
1855912
706ce69
 
 
 
 
1855912
706ce69
 
 
 
14e0dfb
1855912
14e0dfb
706ce69
1855912
14e0dfb
 
 
706ce69
 
14e0dfb
706ce69
 
 
 
 
 
14e0dfb
706ce69
14e0dfb
 
706ce69
 
 
 
 
 
 
 
 
 
14e0dfb
706ce69
 
 
 
 
 
 
 
 
 
 
14e0dfb
 
 
 
1855912
 
 
 
706ce69
1855912
706ce69
1855912
 
706ce69
 
1855912
 
706ce69
1855912
706ce69
 
1855912
706ce69
1855912
706ce69
1855912
 
 
14e0dfb
706ce69
1855912
 
14e0dfb
 
 
706ce69
1855912
 
 
 
 
 
706ce69
1855912
706ce69
14e0dfb
706ce69
14e0dfb
1855912
706ce69
 
14e0dfb
 
706ce69
14e0dfb
 
 
 
706ce69
 
14e0dfb
1855912
 
706ce69
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
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()