Spaces:
Sleeping
Sleeping
File size: 4,494 Bytes
84930b1 4fedcc3 84930b1 6108bd3 84930b1 babde2b 84930b1 6108bd3 84930b1 6108bd3 84930b1 6108bd3 84930b1 6108bd3 84930b1 6108bd3 84930b1 |
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 |
from flask import Flask, render_template_string, jsonify
from apscheduler.schedulers.background import BackgroundScheduler
import subprocess
import threading
from datetime import datetime
app = Flask(__name__)
execution_logs = []
MAX_LOG_ENTRIES = 1000
def run_cli_script():
"""Runs cli.py and streams logs in real-time to both UI and terminal."""
global execution_logs # Declare the global variable
timestamp = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
try:
process = subprocess.Popen(
["python3", "cli.py"],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, # Merge stdout and stderr
text=True,
bufsize=1
)
for line in process.stdout:
execution_logs.append({'time': timestamp, 'output': line.strip(), 'error': ''})
print(line, end="")
# Trim logs efficiently
if len(execution_logs) > MAX_LOG_ENTRIES:
execution_logs = execution_logs[-MAX_LOG_ENTRIES:]
except Exception as e:
execution_logs.append({'time': timestamp, 'output': '', 'error': str(e)})
print(f"Error: {str(e)}")
def start_initial_run():
threading.Thread(target=run_cli_script, daemon=True).start()
scheduler = BackgroundScheduler(daemon=True)
scheduler.add_job(
run_cli_script,
'interval',
hours=3,
id='main_job',
next_run_time=datetime.now()
)
scheduler.start()
start_initial_run()
@app.route('/')
def home():
"""Main UI displaying logs and next run time."""
job = scheduler.get_job('main_job')
next_run = job.next_run_time.strftime('%Y-%m-%d %H:%M:%S UTC') if job else 'N/A'
return render_template_string('''
<!DOCTYPE html>
<html>
<head>
<title>Script Scheduler</title>
<script>
function fetchLogs() {
fetch('/logs')
.then(response => response.json())
.then(data => {
let logBox = document.getElementById("log-box");
logBox.innerHTML = "";
data.logs.forEach(log => {
let logEntry = "<div class='timestamp'>" + log.time + "</div>";
if (log.output) logEntry += "<div class='output'>" + log.output + "</div>";
if (log.error) logEntry += "<div class='error'>" + log.error + "</div>";
logEntry += "<hr>";
logBox.innerHTML += logEntry;
});
logBox.scrollTop = logBox.scrollHeight;
});
}
setInterval(fetchLogs, 2000);
window.onload = fetchLogs;
</script>
<style>
body { font-family: Arial, sans-serif; padding: 20px; }
.log-box {
background: #000;
color: #0f0;
padding: 15px;
border-radius: 5px;
margin-top: 20px;
white-space: pre-wrap;
max-height: 400px;
overflow-y: auto;
}
.timestamp { color: #888; margin-bottom: 10px; }
.error { color: #ff4444; }
</style>
</head>
<body>
<h1>Script Scheduler</h1>
<p>Next run: {{ next_run }}</p>
<h2>Latest Execution Logs</h2>
<div id="log-box" class="log-box"></div>
<p><a href="/force-run">Trigger Manual Run</a></p>
<p><a href="/run-check">Check Scheduler Status</a></p>
</body>
</html>
''', next_run=next_run)
@app.route('/logs')
def logs():
"""Returns logs as JSON for AJAX polling."""
return jsonify({'logs': execution_logs})
@app.route('/force-run')
def force_run():
"""Manually trigger the script execution."""
threading.Thread(target=run_cli_script, daemon=True).start()
return "Script executed manually", 200
@app.route('/run-check')
def run_check():
"""Check if the scheduler is still running."""
if not scheduler.running:
print("Scheduler was stopped! Restarting...")
scheduler.start()
return "Scheduler is running", 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=7860)
|