from __future__ import annotations from pathlib import Path from flask import Flask, request, url_for from flask_socketio import SocketIO from .config import SECRET_KEY from .db import init_db from .utils import file_md5 socketio = SocketIO(cors_allowed_origins="*", ping_timeout=30, async_mode="threading") _static_md5_cache: dict[tuple, str] = {} def create_app() -> Flask: app = Flask(__name__) app.secret_key = SECRET_KEY @app.context_processor def static_helpers(): def static_url(filename: str) -> str: path = Path(app.static_folder or "") / filename try: stat = path.stat() key = (filename, stat.st_mtime_ns, stat.st_size) version = _static_md5_cache.get(key) if not version: _static_md5_cache.clear() version = file_md5(path) _static_md5_cache[key] = version return url_for("static", filename=filename, v=version) except OSError: return url_for("static", filename=filename) return {"static_url": static_url} @app.after_request def cache_headers(response): response.headers.pop('Content-Disposition', None) if request.endpoint == "static": response.headers["Cache-Control"] = "public, max-age=31536000, immutable" else: response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate" response.headers["Pragma"] = "no-cache" response.headers["Expires"] = "0" return response from .routes.main import bp as main_bp from .routes.api import bp as api_bp app.register_blueprint(main_bp) app.register_blueprint(api_bp) init_db() socketio.init_app(app) from .services.workers import set_socketio set_socketio(socketio) from .services.websocket import register_socketio_handlers register_socketio_handlers(socketio) from .services.startup_config import schedule_startup_config_apply schedule_startup_config_apply(socketio) return app