diff --git a/app.py b/app.py index 2503754..bea22ba 100755 --- a/app.py +++ b/app.py @@ -10,7 +10,7 @@ import diskcache import threading import json import time -from flask_socketio import SocketIO +from flask_socketio import SocketIO, emit import geoip2.database from functools import lru_cache from urllib.parse import urlparse, unquote @@ -34,7 +34,8 @@ if os.environ.get('FLASK_ENV') == 'production': app.add_url_rule('/dashboard', view_func=a.dashboard) app.add_url_rule('/network', view_func=a.network) -socketio = SocketIO(app) +socketio = SocketIO(app, async_mode='eventlet') +background_thread_running = False # Global variables to track the number of connected clients and the background thread clients_connected = 0 @@ -312,41 +313,40 @@ def crawl_and_cache(subpath): return json.dumps({"cached_files": cached_files}, indent=4), 200 def query_recent_connections(): - global clients_connected - last_connections = None # Initialize with None to ensure the first emit happens - while clients_connected > 0: - rows = a.return_file_access() + global clients_connected, background_thread_running + background_thread_running = True + last_connections = None + try: + while clients_connected > 0: + rows = a.return_file_access() + connections = [ + { + 'timestamp': row[0], + 'full_path': row[1], + 'ip_address': row[2], + 'user_agent': row[3], + 'referrer': row[4] + } + for row in rows + ] - # Convert rows to dictionaries for the client. - connections = [ - { - 'timestamp': row[0], - 'full_path': row[1], - 'ip_address': row[2], - 'user_agent': row[3], - 'referrer': row[4] - } - for row in rows - ] + if connections != last_connections: + socketio.emit('recent_connections', connections) + last_connections = connections.copy() - # Only emit if there's a change compared to the previous connections. - if connections != last_connections: - socketio.emit('recent_connections', connections) - last_connections = connections.copy() # Store a copy of the current state - - time.sleep(1) - - print("No clients connected; stopping query thread.") + socketio.sleep(1) + finally: + background_thread_running = False + print("No clients connected; stopping query thread.") @socketio.on('connect') -def handle_connect(): - global clients_connected, background_thread +def handle_connect(auth=None): + global clients_connected, background_thread_running clients_connected += 1 print("Client connected. Total clients:", clients_connected) with thread_lock: - # Start the background task if it's not already running. - if background_thread is None or not background_thread.is_alive(): - background_thread = socketio.start_background_task(query_recent_connections) + if not background_thread_running: + socketio.start_background_task(query_recent_connections) print("Started background query task.") @socketio.on('disconnect') @@ -355,6 +355,20 @@ def handle_disconnect(): clients_connected -= 1 print("Client disconnected. Total clients:", clients_connected) +@socketio.on('request_initial_data') +def handle_request_initial_data(): + rows = a.return_file_access() + connections = [ + { + 'timestamp': row[0], + 'full_path': row[1], + 'ip_address': row[2], + 'user_agent': row[3], + 'referrer': row[4] + } + for row in rows + ] + emit('recent_connections', connections) # Catch-all route to serve the single-page application template. @app.route('/', defaults={'path': ''}) @@ -363,5 +377,5 @@ def handle_disconnect(): def index(path): return render_template("app.html") -if __name__ == '__main__': +if __name__ == '__main__': socketio.run(app, debug=True, host='0.0.0.0') diff --git a/docker-compose.yml b/docker-compose.yml index 2331184..b1a0c62 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,40 +16,32 @@ services: propagation: rshared environment: - FLASK_APP=app.py - - FLASK_RUN_HOST=0.0.0.0 - FLASK_ENV=production networks: - traefik labels: - "traefik.enable=true" - # ---------------------------------------------------- - # HTTP router: Listen on entrypoint "web" (port 80) - # and apply a middleware to force redirect to HTTPS - # ---------------------------------------------------- + # HTTP router (port 80), redirecting to HTTPS - "traefik.http.routers.bethaus-app.rule=Host(`app.bethaus-speyer.de`)" - "traefik.http.routers.bethaus-app.entrypoints=web" - "traefik.http.routers.bethaus-app.middlewares=redirect-to-https" - - # This is the "redirect-to-https" middleware definition - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" - # ----------------------------------------------------- - # HTTPS router: Listen on entrypoint "websecure" - # using TLS via your ACME (Let's Encrypt) resolver - # ----------------------------------------------------- + # HTTPS router (TLS via Let's Encrypt) - "traefik.http.routers.bethaus-app-secure.rule=Host(`app.bethaus-speyer.de`)" - "traefik.http.routers.bethaus-app-secure.entrypoints=websecure" - "traefik.http.routers.bethaus-app-secure.tls=true" - "traefik.http.routers.bethaus-app-secure.tls.certresolver=myresolver" - # The service’s internal port + # Internal port - "traefik.http.services.bethaus-app.loadbalancer.server.port=5000" + # Production-ready Gunicorn command with eventlet command: > - sh -c "pip install -r requirements.txt && flask run" + sh -c "pip install -r requirements.txt && + gunicorn --worker-class eventlet -w 1 -b 0.0.0.0:5000 app:app" networks: traefik: external: true - diff --git a/requirements.txt b/requirements.txt index 1ad2786..c1af722 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,5 @@ flask_socketio pillow diskcache geoip2 +gunicorn +eventlet diff --git a/templates/network.html b/templates/network.html index 3defed6..6ce6d71 100644 --- a/templates/network.html +++ b/templates/network.html @@ -53,33 +53,27 @@ -