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 @@
-