From b74eaca83f3a551518244e91685d111233d36304 Mon Sep 17 00:00:00 2001 From: dgtlmoon Date: Wed, 28 May 2025 11:13:47 +0200 Subject: [PATCH] Switch to eventlet as handler, UI option to enable/disable --- changedetectionio/__init__.py | 104 +++--------------- .../settings/templates/settings.html | 4 +- changedetectionio/forms.py | 1 + changedetectionio/model/App.py | 1 + changedetectionio/realtime/socket_server.py | 62 ++++++----- changedetectionio/templates/base.html | 1 - 6 files changed, 56 insertions(+), 117 deletions(-) diff --git a/changedetectionio/__init__.py b/changedetectionio/__init__.py index 0cc72250..03fb23ac 100644 --- a/changedetectionio/__init__.py +++ b/changedetectionio/__init__.py @@ -7,13 +7,15 @@ __version__ = '0.49.18' from changedetectionio.strtobool import strtobool from json.decoder import JSONDecodeError import os +os.environ['EVENTLET_NO_GREENDNS'] = 'yes' +import eventlet +eventlet.monkey_patch() + import getopt import platform import signal -import socket -import sys -from werkzeug.serving import run_simple +import sys from changedetectionio import store from changedetectionio.flask_app import changedetection_app from loguru import logger @@ -52,9 +54,9 @@ def main(): datastore_path = None do_cleanup = False - host = '' + host = "0.0.0.0" ipv6_enabled = False - port = os.environ.get('PORT') or 5000 + port = int(os.environ.get('PORT', 5000)) ssl_mode = False # On Windows, create and use a default path. @@ -150,6 +152,11 @@ def main(): app = changedetection_app(app_config, datastore) + # Get the SocketIO instance from the Flask app (created in flask_app.py) + from changedetectionio.flask_app import socketio_server + global socketio + socketio = socketio_server + signal.signal(signal.SIGTERM, sigshutdown_handler) signal.signal(signal.SIGINT, sigshutdown_handler) @@ -201,87 +208,12 @@ def main(): from werkzeug.middleware.proxy_fix import ProxyFix app.wsgi_app = ProxyFix(app.wsgi_app, x_prefix=1, x_host=1) - s_type = socket.AF_INET6 if ipv6_enabled else socket.AF_INET - # Get socketio_server from flask_app - from changedetectionio.flask_app import socketio_server + # SocketIO instance is already initialized in flask_app.py - if socketio_server and datastore.data['settings']['application']['ui'].get('open_diff_in_new_tab'): - logger.info("Starting server with Socket.IO support (using threading)...") - - # Use Flask-SocketIO's run method with error handling for Werkzeug warning - # This is the cleanest approach that works with all Flask-SocketIO versions - # Use '0.0.0.0' as the default host if none is specified - # This will listen on all available interfaces - listen_host = '0.0.0.0' if host == '' else host - logger.info(f"Using host: {listen_host} and port: {port}") - - try: - # First try with the allow_unsafe_werkzeug parameter (newer versions) - if ssl_mode: - socketio_server.run( - app, - host=listen_host, - port=int(port), - certfile='cert.pem', - keyfile='privkey.pem', - debug=False, - use_reloader=False, - allow_unsafe_werkzeug=True # Only in newer versions - ) - else: - socketio_server.run( - app, - host=listen_host, - port=int(port), - debug=False, - use_reloader=False, - allow_unsafe_werkzeug=True # Only in newer versions - ) - except TypeError: - # If allow_unsafe_werkzeug is not a valid parameter, try without it - logger.info("Falling back to basic run method without allow_unsafe_werkzeug") - # Override the werkzeug safety check by setting an environment variable - os.environ['WERKZEUG_RUN_MAIN'] = 'true' - if ssl_mode: - socketio_server.run( - app, - host=listen_host, - port=int(port), - certfile='cert.pem', - keyfile='privkey.pem', - debug=False, - use_reloader=False - ) - else: - socketio_server.run( - app, - host=listen_host, - port=int(port), - debug=False, - use_reloader=False - ) + # Launch using eventlet SocketIO run method for proper integration + if ssl_mode: + socketio.run(app, host=host, port=int(port), debug=False, + certfile='cert.pem', keyfile='privkey.pem') else: - logger.warning("Socket.IO server not initialized, falling back to standard WSGI server") - # Fallback to standard WSGI server if socketio_server is not available - listen_host = '0.0.0.0' if host == '' else host - if ssl_mode: - # Use Werkzeug's run_simple with SSL support - run_simple( - hostname=listen_host, - port=int(port), - application=app, - use_reloader=False, - use_debugger=False, - ssl_context=('cert.pem', 'privkey.pem') - ) - else: - # Use Werkzeug's run_simple for standard HTTP - run_simple( - hostname=listen_host, - port=int(port), - application=app, - use_reloader=False, - use_debugger=False - ) - + socketio.run(app, host=host, port=int(port), debug=False) diff --git a/changedetectionio/blueprint/settings/templates/settings.html b/changedetectionio/blueprint/settings/templates/settings.html index 5f302331..7efe2f70 100644 --- a/changedetectionio/blueprint/settings/templates/settings.html +++ b/changedetectionio/blueprint/settings/templates/settings.html @@ -247,9 +247,9 @@ nav Enable this setting to open the diff page in a new tab. If disabled, the diff page will open in the current tab.
- Enable realtime updates in the UI + {{ render_checkbox_field(form.application.form.ui.form.socket_io_enabled, class="socket_io_enabled") }} + Realtime UI Updates Enabled - (Restart required if this is changed)
-