From e999fc77c232ca4c75e7476ecd15e2877c179bd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Gruszczy=C5=84ski?= Date: Sat, 14 Feb 2026 09:46:26 +0100 Subject: [PATCH] app --- app.py | 101 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 76 insertions(+), 25 deletions(-) diff --git a/app.py b/app.py index 8751d63..6cf79a0 100644 --- a/app.py +++ b/app.py @@ -17,6 +17,7 @@ import config from cve_handler import CVEHandler, update_all_vendors import api + def setup_logging(): log_level = getattr(logging, config.LOG_LEVEL.upper(), logging.INFO) @@ -60,16 +61,19 @@ if not config.DEBUG: app.register_blueprint(api.api_bp, url_prefix='/api') cve_handler = CVEHandler() + @app.context_processor def inject_config(): return {'config': config} + def add_security_headers(response): if config.ENABLE_SECURITY_HEADERS: for header, value in config.SECURITY_HEADERS.items(): response.headers[header] = value return response + def gzip_response(f): @wraps(f) def decorated_function(*args, **kwargs): @@ -99,6 +103,7 @@ def gzip_response(f): return response return decorated_function + def etag_support(f): @wraps(f) def decorated_function(*args, **kwargs): @@ -121,12 +126,14 @@ def etag_support(f): return decorated_function + @app.route('/') @gzip_response @etag_support def index(): return render_template('index.html', vendors=config.VENDORS) + @app.route('/health') def health(): try: @@ -166,10 +173,12 @@ def health(): 'error': str(e) }), 503 + @app.route('/favicon.ico') def favicon(): return '', 204 + @app.route('/version') def version(): return jsonify({ @@ -179,12 +188,14 @@ def version(): 'flask_version': '3.0.2' }) + @app.errorhandler(404) def not_found(error): if request.path.startswith('/api/'): return jsonify({'error': 'Endpoint not found'}), 404 return render_template('404.html'), 404 + @app.errorhandler(500) def internal_error(error): logger.error(f"Internal error: {error}") @@ -192,6 +203,7 @@ def internal_error(error): return jsonify({'error': 'Internal server error'}), 500 return render_template('500.html'), 500 + @app.after_request def after_request(response): response = add_security_headers(response) @@ -204,6 +216,7 @@ def after_request(response): return response + def background_update_task(): logger.info("Background update task started") time.sleep(60) @@ -225,31 +238,68 @@ def background_update_task(): def start_background_tasks(): - if config.ENABLE_AUTO_UPDATE: - update_thread = threading.Thread( - target=background_update_task, - daemon=True, - name="CVE-Update-Thread" - ) - update_thread.start() - logger.info("Auto-update enabled: background task started") - else: - logger.info("Auto-update disabled") + is_gunicorn = ( + 'gunicorn' in os.environ.get('SERVER_SOFTWARE', '').lower() or + os.environ.get('GUNICORN_CMD_ARGS') is not None + ) - if config.DISCORD_BOT_ENABLED: - try: - from discord_bot import start_discord_bot - discord_thread = threading.Thread( - target=start_discord_bot, - daemon=True, - name="Discord-Bot-Thread" - ) - discord_thread.start() - logger.info("Discord bot started") - except ImportError: - logger.warning("discord.py not installed, Discord bot disabled") - except Exception as e: - logger.error(f"Failed to start Discord bot: {e}", exc_info=True) + is_dev_mode = __name__ == '__main__' + + if is_gunicorn: + logger.info("=" * 70) + logger.info("PRODUCTION MODE (Gunicorn)") + logger.info("=" * 70) + logger.info("Background tasks handled by separate containers:") + logger.info(" Scheduler: cve-monitor-scheduler") + logger.info(" Discord Bot: cve-monitor-discord") + logger.info("=" * 70) + return + + if is_dev_mode: + logger.info("=" * 70) + logger.info("DEVELOPMENT MODE (Standalone Flask)") + logger.info("=" * 70) + logger.info("Starting background tasks in threads...") + logger.info("") + + if config.ENABLE_AUTO_UPDATE: + try: + update_thread = threading.Thread( + target=background_update_task, + daemon=True, + name="CVE-Update-Thread" + ) + update_thread.start() + logger.info(" Scheduler thread: STARTED") + except Exception as e: + logger.error(f" Scheduler thread: FAILED - {e}") + else: + logger.info(" Scheduler thread: DISABLED") + + if config.DISCORD_BOT_ENABLED: + try: + from discord_bot import start_discord_bot + + discord_thread = threading.Thread( + target=start_discord_bot, + daemon=True, + name="Discord-Bot-Thread" + ) + discord_thread.start() + logger.info(" Discord bot thread: STARTED") + + except ImportError: + logger.warning(" Discord bot thread: FAILED - discord.py not installed") + except Exception as e: + logger.error(f" Discord bot thread: FAILED - {e}") + else: + logger.info(" Discord bot thread: DISABLED") + + logger.info("") + logger.info("=" * 70) + else: + logger.info("Production mode: background tasks in separate containers") + def initialize_app(): logger.info(f"{'='*60}") @@ -282,6 +332,7 @@ def initialize_app(): logger.info(f"{'='*60}") start_background_tasks() + _initialized = False if __name__ == '__main__': @@ -300,4 +351,4 @@ if __name__ == '__main__': else: if not _initialized: initialize_app() - _initialized = True \ No newline at end of file + _initialized = True