mirror of
				https://github.com/bunny-lab-io/Borealis.git
				synced 2025-10-26 15:21:57 -06:00 
			
		
		
		
	Merge pull request #144 from bunny-lab-io:codex/review-code-migration-instructions
Stage 2 - Port configuration and dependency loading into the Engine factory Implemented
This commit is contained in:
		| @@ -13,11 +13,11 @@ Lastly, everytime that you complete a stage, you will create a pull request name | ||||
|   - [x] Scaffold Data/Engine/server.py with the create_app(config) factory and stub service registration hooks. | ||||
|   - [x] Return a shared context object containing handles such as the database path, logger, and scheduler. | ||||
|   - [x] Update project tooling so the Engine runtime can be launched alongside the legacy path. | ||||
| - [ ] **Stage 2 — Port configuration and dependency loading into the Engine factory** | ||||
|   - [ ] Extract configuration loading logic from Data/Server/server.py into Data/Engine/config.py helpers. | ||||
|   - [ ] Verify context parity between Engine and legacy startup. | ||||
|   - [ ] Initialize logging to Logs/Server/server.log when Engine mode is active. | ||||
|   - [ ] Document Engine launch paths and configuration requirements in module docstrings. | ||||
| - [x] **Stage 2 — Port configuration and dependency loading into the Engine factory** | ||||
|   - [x] Extract configuration loading logic from Data/Server/server.py into Data/Engine/config.py helpers. | ||||
|   - [x] Verify context parity between Engine and legacy startup. | ||||
|   - [x] Initialize logging to Logs/Server/server.log when Engine mode is active. | ||||
|   - [x] Document Engine launch paths and configuration requirements in module docstrings. | ||||
| - [ ] **Stage 3 — Introduce API blueprints and service adapters** | ||||
|   - [ ] Create domain-focused API blueprints and register_api entry point. | ||||
|   - [ ] Mirror route behaviour from the legacy server via service adapters. | ||||
| @@ -41,3 +41,7 @@ Lastly, everytime that you complete a stage, you will create a pull request name | ||||
|   - [ ] Provide register_realtime hook for the Engine factory. | ||||
|   - [ ] Add integration tests or smoke checks for key events. | ||||
|   - [ ] Update legacy server to consume Engine WebSocket registration. | ||||
|  | ||||
| ## Current Status | ||||
| - **Stage:** Stage 2 — Port configuration and dependency loading into the Engine factory (completed) | ||||
| - **Active Task:** Awaiting next stage instructions. | ||||
|   | ||||
| @@ -1,9 +1,10 @@ | ||||
| """Borealis Engine runtime package. | ||||
|  | ||||
| This package houses the next-generation server runtime that will gradually | ||||
| replace :mod:`Data.Server.server`. Stage 1 focuses on providing a skeleton | ||||
| application factory and service placeholders so later stages can port | ||||
| features incrementally. | ||||
| replace :mod:`Data.Server.server`. Stage 1 delivered the structural skeleton | ||||
| for the Flask/Socket.IO factory; Stage 2 layers in configuration loading and | ||||
| logging parity via :mod:`Data.Engine.config` so Engine launches honour the | ||||
| same environment variables and log destinations as the legacy server. | ||||
| """ | ||||
|  | ||||
| from .server import create_app, EngineContext  # re-export for convenience | ||||
|   | ||||
| @@ -1,4 +1,11 @@ | ||||
| """Command-line bootstrapper for the Stage 1 Engine runtime.""" | ||||
| """Entrypoint helpers for running the Borealis Engine runtime. | ||||
|  | ||||
| The bootstrapper assembles configuration via :func:`Data.Engine.config.load_runtime_config` | ||||
| before delegating to :func:`Data.Engine.server.create_app`.  It mirrors the | ||||
| legacy server defaults by binding to ``0.0.0.0:5001`` and honouring the | ||||
| ``BOREALIS_ENGINE_*`` environment overrides for bind host/port. | ||||
| """ | ||||
|  | ||||
| from __future__ import annotations | ||||
|  | ||||
| import os | ||||
|   | ||||
							
								
								
									
										254
									
								
								Data/Engine/config.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										254
									
								
								Data/Engine/config.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,254 @@ | ||||
| """Configuration helpers for the Borealis Engine runtime. | ||||
|  | ||||
| Stage 2 of the migration focuses on lifting the legacy configuration loading | ||||
| behaviour from :mod:`Data.Server.server` into reusable helpers so the Engine | ||||
| start-up path honours the same environment variables, filesystem layout, and | ||||
| logging expectations.  This module documents the supported launch parameters | ||||
| and exposes typed helpers that the application factory consumes. | ||||
|  | ||||
| Launch overview | ||||
| --------------- | ||||
| The Engine can be started via :func:`Data.Engine.bootstrapper.main` or by | ||||
| invoking :func:`Data.Engine.server.create_app` manually.  Configuration is | ||||
| assembled from (in precedence order): | ||||
|  | ||||
| ``config`` mapping overrides provided to :func:`load_runtime_config`, | ||||
| environment variables prefixed with ``BOREALIS_``, and finally built-in | ||||
| defaults that mirror the legacy server runtime.  Key environment variables are | ||||
|  | ||||
| ``BOREALIS_DATABASE_PATH``  path to the SQLite database file.  Defaults to | ||||
| ``<ProjectRoot>/database.db``. | ||||
| ``BOREALIS_CORS_ORIGINS``   comma separated list of allowed origins for CORS. | ||||
| ``BOREALIS_SECRET``         Flask session secret key. | ||||
| ``BOREALIS_COOKIE_*``       Session cookie policies (``SAMESITE``, ``SECURE``, | ||||
|                             ``DOMAIN``). | ||||
| ``BOREALIS_TLS_*``          TLS certificate, private key, and bundle paths. | ||||
|  | ||||
| When TLS values are not provided explicitly the Engine falls back to the | ||||
| certificate helper shipped with the legacy server, ensuring bundling parity. | ||||
| Logs are written to ``Logs/Server/server.log`` with daily rotation so the new | ||||
| runtime integrates with existing operational practices. | ||||
| """ | ||||
|  | ||||
| from __future__ import annotations | ||||
|  | ||||
| import logging | ||||
| import os | ||||
| from dataclasses import asdict, dataclass, field | ||||
| from logging.handlers import TimedRotatingFileHandler | ||||
| from pathlib import Path | ||||
| from typing import Any, List, Mapping, MutableMapping, Optional, Sequence | ||||
|  | ||||
| try:  # pragma: no-cover - optional dependency during early migration stages. | ||||
|     from Modules.crypto import certificates  # type: ignore | ||||
| except Exception:  # pragma: no-cover - Engine configuration still works without it. | ||||
|     certificates = None  # type: ignore[assignment] | ||||
|  | ||||
|  | ||||
| ENGINE_DIR = Path(__file__).resolve().parent | ||||
| PROJECT_ROOT = ENGINE_DIR.parent.parent | ||||
| DEFAULT_DATABASE_PATH = PROJECT_ROOT / "database.db" | ||||
| LOG_FILE_PATH = PROJECT_ROOT / "Logs" / "Server" / "server.log" | ||||
|  | ||||
|  | ||||
| def _ensure_parent(path: Path) -> None: | ||||
|     try: | ||||
|         path.parent.mkdir(parents=True, exist_ok=True) | ||||
|     except Exception: | ||||
|         # Directory creation failure is non-fatal; subsequent file operations | ||||
|         # will surface the issue with clearer context. | ||||
|         pass | ||||
|  | ||||
|  | ||||
| def _resolve_static_folder() -> str: | ||||
|     candidates = [ | ||||
|         ENGINE_DIR / "web-interface" / "build", | ||||
|         ENGINE_DIR / "web-interface" / "dist", | ||||
|         ENGINE_DIR / "web-interface", | ||||
|     ] | ||||
|     for candidate in candidates: | ||||
|         absolute = candidate.resolve() | ||||
|         if absolute.is_dir(): | ||||
|             return str(absolute) | ||||
|     return str(candidates[0].resolve()) | ||||
|  | ||||
|  | ||||
| def _parse_origins(raw: Optional[Any]) -> Optional[List[str]]: | ||||
|     if raw is None: | ||||
|         return None | ||||
|     if isinstance(raw, str): | ||||
|         parts = [part.strip() for part in raw.split(",")] | ||||
|     elif isinstance(raw, Sequence): | ||||
|         parts = [str(part).strip() for part in raw] | ||||
|     else: | ||||
|         return None | ||||
|     origins = [part for part in parts if part] | ||||
|     return origins or None | ||||
|  | ||||
|  | ||||
| def _parse_bool(raw: Any, *, default: bool = False) -> bool: | ||||
|     if raw is None: | ||||
|         return default | ||||
|     if isinstance(raw, bool): | ||||
|         return raw | ||||
|     lowered = str(raw).strip().lower() | ||||
|     if lowered in {"1", "true", "yes", "on"}: | ||||
|         return True | ||||
|     if lowered in {"0", "false", "no", "off"}: | ||||
|         return False | ||||
|     return default | ||||
|  | ||||
|  | ||||
| def _discover_tls_material(config: Mapping[str, Any]) -> Sequence[Optional[str]]: | ||||
|     cert_path = config.get("TLS_CERT_PATH") or os.environ.get("BOREALIS_TLS_CERT") or None | ||||
|     key_path = config.get("TLS_KEY_PATH") or os.environ.get("BOREALIS_TLS_KEY") or None | ||||
|     bundle_path = config.get("TLS_BUNDLE_PATH") or os.environ.get("BOREALIS_TLS_BUNDLE") or None | ||||
|  | ||||
|     if certificates and not all([cert_path, key_path, bundle_path]): | ||||
|         try: | ||||
|             auto_cert, auto_key, auto_bundle = certificates.certificate_paths() | ||||
|         except Exception: | ||||
|             auto_cert = auto_key = auto_bundle = None | ||||
|         else: | ||||
|             cert_path = cert_path or auto_cert | ||||
|             key_path = key_path or auto_key | ||||
|             bundle_path = bundle_path or auto_bundle | ||||
|  | ||||
|     if cert_path: | ||||
|         os.environ.setdefault("BOREALIS_TLS_CERT", str(cert_path)) | ||||
|     if key_path: | ||||
|         os.environ.setdefault("BOREALIS_TLS_KEY", str(key_path)) | ||||
|     if bundle_path: | ||||
|         os.environ.setdefault("BOREALIS_TLS_BUNDLE", str(bundle_path)) | ||||
|  | ||||
|     return cert_path, key_path, bundle_path | ||||
|  | ||||
|  | ||||
| @dataclass | ||||
| class EngineSettings: | ||||
|     """Resolved configuration values for the Engine runtime.""" | ||||
|  | ||||
|     database_path: str | ||||
|     static_folder: str | ||||
|     cors_origins: Optional[List[str]] | ||||
|     secret_key: str | ||||
|     session_cookie_samesite: str | ||||
|     session_cookie_secure: bool | ||||
|     session_cookie_domain: Optional[str] | ||||
|     tls_cert_path: Optional[str] | ||||
|     tls_key_path: Optional[str] | ||||
|     tls_bundle_path: Optional[str] | ||||
|     log_file: str | ||||
|     raw: MutableMapping[str, Any] = field(default_factory=dict) | ||||
|  | ||||
|     def to_flask_config(self) -> MutableMapping[str, Any]: | ||||
|         config: MutableMapping[str, Any] = { | ||||
|             "SESSION_COOKIE_HTTPONLY": True, | ||||
|             "SESSION_COOKIE_SAMESITE": self.session_cookie_samesite, | ||||
|             "SESSION_COOKIE_SECURE": self.session_cookie_secure, | ||||
|             "PREFERRED_URL_SCHEME": "https", | ||||
|         } | ||||
|         if self.session_cookie_domain: | ||||
|             config["SESSION_COOKIE_DOMAIN"] = self.session_cookie_domain | ||||
|         return config | ||||
|  | ||||
|     def as_dict(self) -> MutableMapping[str, Any]: | ||||
|         data = asdict(self) | ||||
|         data["raw"] = dict(self.raw) | ||||
|         return data | ||||
|  | ||||
|  | ||||
| def load_runtime_config(overrides: Optional[Mapping[str, Any]] = None) -> EngineSettings: | ||||
|     """Resolve Engine configuration values. | ||||
|  | ||||
|     Parameters | ||||
|     ---------- | ||||
|     overrides: | ||||
|         Optional mapping of explicit configuration values.  These take | ||||
|         precedence over environment variables and built-in defaults. | ||||
|     """ | ||||
|  | ||||
|     runtime_config: MutableMapping[str, Any] = dict(overrides or {}) | ||||
|  | ||||
|     database_path = str( | ||||
|         runtime_config.get("DATABASE_PATH") | ||||
|         or os.environ.get("BOREALIS_DATABASE_PATH") | ||||
|         or DEFAULT_DATABASE_PATH | ||||
|     ) | ||||
|     database_path = os.path.abspath(database_path) | ||||
|     _ensure_parent(Path(database_path)) | ||||
|  | ||||
|     static_folder = str(runtime_config.get("STATIC_FOLDER") or _resolve_static_folder()) | ||||
|  | ||||
|     cors_origins = _parse_origins( | ||||
|         runtime_config.get("CORS_ORIGINS") or os.environ.get("BOREALIS_CORS_ORIGINS") | ||||
|     ) | ||||
|  | ||||
|     secret_key = str(runtime_config.get("SECRET_KEY") or os.environ.get("BOREALIS_SECRET") or "borealis-dev-secret") | ||||
|  | ||||
|     session_cookie_samesite = str( | ||||
|         runtime_config.get("SESSION_COOKIE_SAMESITE") | ||||
|         or os.environ.get("BOREALIS_COOKIE_SAMESITE") | ||||
|         or "Lax" | ||||
|     ) | ||||
|  | ||||
|     session_cookie_secure = _parse_bool( | ||||
|         runtime_config.get("SESSION_COOKIE_SECURE"), | ||||
|         default=_parse_bool(os.environ.get("BOREALIS_COOKIE_SECURE"), default=False), | ||||
|     ) | ||||
|  | ||||
|     session_cookie_domain = runtime_config.get("SESSION_COOKIE_DOMAIN") or os.environ.get("BOREALIS_COOKIE_DOMAIN") | ||||
|     session_cookie_domain = str(session_cookie_domain) if session_cookie_domain else None | ||||
|  | ||||
|     tls_cert_path, tls_key_path, tls_bundle_path = _discover_tls_material(runtime_config) | ||||
|  | ||||
|     log_file = str(runtime_config.get("LOG_FILE") or LOG_FILE_PATH) | ||||
|     _ensure_parent(Path(log_file)) | ||||
|  | ||||
|     settings = EngineSettings( | ||||
|         database_path=database_path, | ||||
|         static_folder=static_folder, | ||||
|         cors_origins=cors_origins, | ||||
|         secret_key=secret_key, | ||||
|         session_cookie_samesite=session_cookie_samesite, | ||||
|         session_cookie_secure=session_cookie_secure, | ||||
|         session_cookie_domain=session_cookie_domain, | ||||
|         tls_cert_path=tls_cert_path if tls_cert_path else None, | ||||
|         tls_key_path=tls_key_path if tls_key_path else None, | ||||
|         tls_bundle_path=tls_bundle_path if tls_bundle_path else None, | ||||
|         log_file=str(log_file), | ||||
|         raw=runtime_config, | ||||
|     ) | ||||
|     return settings | ||||
|  | ||||
|  | ||||
| def initialise_engine_logger(settings: EngineSettings, name: str = "borealis.engine") -> logging.Logger: | ||||
|     """Configure the Engine logger to write to the shared server log.""" | ||||
|  | ||||
|     logger = logging.getLogger(name) | ||||
|     if not logger.handlers: | ||||
|         formatter = logging.Formatter("%(asctime)s-%(name)s-%(levelname)s: %(message)s") | ||||
|  | ||||
|         stream_handler = logging.StreamHandler() | ||||
|         stream_handler.setFormatter(formatter) | ||||
|         logger.addHandler(stream_handler) | ||||
|  | ||||
|         file_handler = TimedRotatingFileHandler( | ||||
|             settings.log_file, | ||||
|             when="midnight", | ||||
|             backupCount=0, | ||||
|             encoding="utf-8", | ||||
|         ) | ||||
|         file_handler.setFormatter(formatter) | ||||
|         logger.addHandler(file_handler) | ||||
|  | ||||
|     logger.setLevel(logging.INFO) | ||||
|     logger.propagate = False | ||||
|     return logger | ||||
|  | ||||
|  | ||||
| __all__ = [ | ||||
|     "EngineSettings", | ||||
|     "initialise_engine_logger", | ||||
|     "load_runtime_config", | ||||
| ] | ||||
| @@ -1,18 +1,20 @@ | ||||
| """Stage 1 Borealis Engine application factory. | ||||
| """Stage 2 Borealis Engine application factory. | ||||
|  | ||||
| This module establishes the foundational structure for the Engine runtime so | ||||
| subsequent migration stages can progressively assume responsibility for the | ||||
| API, WebUI, and WebSocket layers. | ||||
| Stage 1 introduced the structural skeleton for the Engine runtime.  Stage 2 | ||||
| builds upon that foundation by centralising configuration handling and logging | ||||
| initialisation so the Engine mirrors the legacy server's start-up behaviour. | ||||
| The factory delegates configuration resolution to :mod:`Data.Engine.config` | ||||
| and emits structured logs to ``Logs/Server/server.log`` to align with the | ||||
| project's operational practices. | ||||
| """ | ||||
| from __future__ import annotations | ||||
|  | ||||
| import logging | ||||
| import os | ||||
| import ssl | ||||
| import sys | ||||
| from dataclasses import dataclass | ||||
| from pathlib import Path | ||||
| from typing import Any, Mapping, MutableMapping, Optional, Tuple | ||||
| from typing import Any, Mapping, Optional, Tuple | ||||
|  | ||||
| import eventlet | ||||
| from flask import Flask | ||||
| @@ -87,10 +89,7 @@ for root in _SEARCH_ROOTS: | ||||
|         if root_str not in sys.path: | ||||
|             sys.path.insert(0, root_str) | ||||
|  | ||||
| try:  # pragma: no-cover - optional during Stage 1 scaffolding. | ||||
|     from Modules.crypto import certificates  # type: ignore | ||||
| except Exception:  # pragma: no-cover - Engine can start without certificate helpers. | ||||
|     certificates = None  # type: ignore[assignment] | ||||
| from .config import EngineSettings, initialise_engine_logger, load_runtime_config | ||||
|  | ||||
|  | ||||
| @dataclass | ||||
| @@ -109,103 +108,27 @@ class EngineContext: | ||||
| __all__ = ["EngineContext", "create_app"] | ||||
|  | ||||
|  | ||||
| def _resolve_static_folder() -> str: | ||||
|     candidates = [ | ||||
|         _ENGINE_DIR / "web-interface" / "build", | ||||
|         _ENGINE_DIR / "web-interface" / "dist", | ||||
|         _ENGINE_DIR / "web-interface", | ||||
|     ] | ||||
|     for candidate in candidates: | ||||
|         absolute = candidate.resolve() | ||||
|         if absolute.is_dir(): | ||||
|             return str(absolute) | ||||
|     # Fall back to the first candidate to maintain parity with the legacy | ||||
|     # behaviour where the folder may not exist yet. | ||||
|     return str(candidates[0].resolve()) | ||||
|  | ||||
|  | ||||
| def _initialise_logger(name: str = "borealis.engine") -> logging.Logger: | ||||
|     logger = logging.getLogger(name) | ||||
|     if not logger.handlers: | ||||
|         handler = logging.StreamHandler() | ||||
|         formatter = logging.Formatter("%(asctime)s-%(name)s-%(levelname)s: %(message)s") | ||||
|         handler.setFormatter(formatter) | ||||
|         logger.addHandler(handler) | ||||
|     logger.setLevel(logging.INFO) | ||||
|     logger.propagate = False | ||||
|     return logger | ||||
|  | ||||
|  | ||||
| def _discover_tls_material(config: Mapping[str, Any]) -> Tuple[Optional[str], Optional[str], Optional[str]]: | ||||
|     cert_path = str(config.get("TLS_CERT_PATH") or os.environ.get("BOREALIS_TLS_CERT") or "") or None | ||||
|     key_path = str(config.get("TLS_KEY_PATH") or os.environ.get("BOREALIS_TLS_KEY") or "") or None | ||||
|     bundle_path = str(config.get("TLS_BUNDLE_PATH") or os.environ.get("BOREALIS_TLS_BUNDLE") or "") or None | ||||
|  | ||||
|     if certificates and not all([cert_path, key_path, bundle_path]): | ||||
|         try: | ||||
|             auto_cert, auto_key, auto_bundle = certificates.certificate_paths() | ||||
|         except Exception: | ||||
|             auto_cert = auto_key = auto_bundle = None | ||||
|         else: | ||||
|             cert_path = cert_path or auto_cert | ||||
|             key_path = key_path or auto_key | ||||
|             bundle_path = bundle_path or auto_bundle | ||||
|  | ||||
|     if cert_path: | ||||
|         os.environ.setdefault("BOREALIS_TLS_CERT", cert_path) | ||||
|     if key_path: | ||||
|         os.environ.setdefault("BOREALIS_TLS_KEY", key_path) | ||||
|     if bundle_path: | ||||
|         os.environ.setdefault("BOREALIS_TLS_BUNDLE", bundle_path) | ||||
|     return cert_path, key_path, bundle_path | ||||
|  | ||||
|  | ||||
| def _coerce_config(source: Optional[Mapping[str, Any]]) -> MutableMapping[str, Any]: | ||||
|     if source is None: | ||||
|         return {} | ||||
|     return dict(source) | ||||
|  | ||||
|  | ||||
| def create_app(config: Optional[Mapping[str, Any]] = None) -> Tuple[Flask, SocketIO, EngineContext]: | ||||
|     """Create the Stage 1 Engine Flask application.""" | ||||
|     """Create the Stage 2 Engine Flask application.""" | ||||
|  | ||||
|     runtime_config: MutableMapping[str, Any] = _coerce_config(config) | ||||
|     logger = _initialise_logger() | ||||
|     settings: EngineSettings = load_runtime_config(config) | ||||
|     logger = initialise_engine_logger(settings) | ||||
|  | ||||
|     database_path = runtime_config.get("DATABASE_PATH") or os.path.abspath( | ||||
|         os.path.join(_ENGINE_DIR, "..", "..", "database.db") | ||||
|     ) | ||||
|     os.makedirs(os.path.dirname(database_path), exist_ok=True) | ||||
|     database_path = settings.database_path | ||||
|  | ||||
|     static_folder = _resolve_static_folder() | ||||
|     static_folder = settings.static_folder | ||||
|     app = Flask(__name__, static_folder=static_folder, static_url_path="") | ||||
|     app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1) | ||||
|  | ||||
|     cors_origins = runtime_config.get("CORS_ORIGINS") or os.environ.get("BOREALIS_CORS_ORIGINS") | ||||
|     cors_origins = settings.cors_origins | ||||
|     if cors_origins: | ||||
|         origins = [origin.strip() for origin in str(cors_origins).split(",") if origin.strip()] | ||||
|         CORS(app, supports_credentials=True, origins=origins) | ||||
|         CORS(app, supports_credentials=True, origins=cors_origins) | ||||
|     else: | ||||
|         CORS(app, supports_credentials=True) | ||||
|  | ||||
|     app.secret_key = runtime_config.get("SECRET_KEY") or os.environ.get("BOREALIS_SECRET", "borealis-dev-secret") | ||||
|     app.secret_key = settings.secret_key | ||||
|  | ||||
|     app.config.update( | ||||
|         SESSION_COOKIE_HTTPONLY=True, | ||||
|         SESSION_COOKIE_SAMESITE=runtime_config.get( | ||||
|             "SESSION_COOKIE_SAMESITE", | ||||
|             os.environ.get("BOREALIS_COOKIE_SAMESITE", "Lax"), | ||||
|         ), | ||||
|         SESSION_COOKIE_SECURE=bool( | ||||
|             str(runtime_config.get("SESSION_COOKIE_SECURE", os.environ.get("BOREALIS_COOKIE_SECURE", "0"))).lower() | ||||
|             in {"1", "true", "yes"} | ||||
|         ), | ||||
|     ) | ||||
|     app.config.setdefault("PREFERRED_URL_SCHEME", "https") | ||||
|  | ||||
|     cookie_domain = runtime_config.get("SESSION_COOKIE_DOMAIN") or os.environ.get("BOREALIS_COOKIE_DOMAIN") | ||||
|     if cookie_domain: | ||||
|         app.config["SESSION_COOKIE_DOMAIN"] = cookie_domain | ||||
|     app.config.update(settings.to_flask_config()) | ||||
|  | ||||
|     socketio = SocketIO( | ||||
|         app, | ||||
| @@ -217,7 +140,11 @@ def create_app(config: Optional[Mapping[str, Any]] = None) -> Tuple[Flask, Socke | ||||
|         }, | ||||
|     ) | ||||
|  | ||||
|     tls_cert_path, tls_key_path, tls_bundle_path = _discover_tls_material(runtime_config) | ||||
|     tls_cert_path, tls_key_path, tls_bundle_path = ( | ||||
|         settings.tls_cert_path, | ||||
|         settings.tls_key_path, | ||||
|         settings.tls_bundle_path, | ||||
|     ) | ||||
|  | ||||
|     context = EngineContext( | ||||
|         database_path=database_path, | ||||
| @@ -226,7 +153,7 @@ def create_app(config: Optional[Mapping[str, Any]] = None) -> Tuple[Flask, Socke | ||||
|         tls_cert_path=tls_cert_path, | ||||
|         tls_key_path=tls_key_path, | ||||
|         tls_bundle_path=tls_bundle_path, | ||||
|         config=runtime_config, | ||||
|         config=settings.as_dict(), | ||||
|     ) | ||||
|  | ||||
|     from .services import API, WebSocket, WebUI  # Local import to avoid circular deps during bootstrap | ||||
|   | ||||
		Reference in New Issue
	
	Block a user