mirror of
https://github.com/bunny-lab-io/Borealis.git
synced 2025-10-26 22:01:59 -06:00
Refine Engine configuration wiring
This commit is contained in:
@@ -5,7 +5,7 @@
|
|||||||
- 1.2 Document environment variables/settings expected by the Engine to keep parity with legacy defaults.
|
- 1.2 Document environment variables/settings expected by the Engine to keep parity with legacy defaults.
|
||||||
- 1.3 Verify Engine logging produces `Logs/Server/engine.log` entries alongside the legacy server.
|
- 1.3 Verify Engine logging produces `Logs/Server/engine.log` entries alongside the legacy server.
|
||||||
|
|
||||||
2. Introduce configuration & dependency wiring
|
[COMPLETED] 2. Introduce configuration & dependency wiring
|
||||||
- 2.1 Create `config/environment.py` loaders mirroring legacy defaults (TLS paths, feature flags).
|
- 2.1 Create `config/environment.py` loaders mirroring legacy defaults (TLS paths, feature flags).
|
||||||
- 2.2 Add settings dataclasses for Flask, Socket.IO, and DB paths; inject them via `server.py`.
|
- 2.2 Add settings dataclasses for Flask, Socket.IO, and DB paths; inject them via `server.py`.
|
||||||
- 2.3 Commit once the Engine can start with equivalent config but no real routes.
|
- 2.3 Commit once the Engine can start with equivalent config but no real routes.
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ def bootstrap() -> EngineRuntime:
|
|||||||
logger.info("bootstrap-started")
|
logger.info("bootstrap-started")
|
||||||
app = create_app(settings)
|
app = create_app(settings)
|
||||||
register_http_interfaces(app)
|
register_http_interfaces(app)
|
||||||
socketio = create_socket_server(app, settings)
|
socketio = create_socket_server(app, settings.socketio)
|
||||||
logger.info("bootstrap-complete")
|
logger.info("bootstrap-complete")
|
||||||
return EngineRuntime(app=app, settings=settings, socketio=socketio)
|
return EngineRuntime(app=app, settings=settings, socketio=socketio)
|
||||||
|
|
||||||
@@ -40,14 +40,14 @@ def main() -> None:
|
|||||||
if socketio is not None:
|
if socketio is not None:
|
||||||
socketio.run( # type: ignore[call-arg]
|
socketio.run( # type: ignore[call-arg]
|
||||||
runtime.app,
|
runtime.app,
|
||||||
host=runtime.settings.host,
|
host=runtime.settings.server.host,
|
||||||
port=runtime.settings.port,
|
port=runtime.settings.server.port,
|
||||||
debug=runtime.settings.debug,
|
debug=runtime.settings.debug,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
runtime.app.run(
|
runtime.app.run(
|
||||||
host=runtime.settings.host,
|
host=runtime.settings.server.host,
|
||||||
port=runtime.settings.port,
|
port=runtime.settings.server.port,
|
||||||
debug=runtime.settings.debug,
|
debug=runtime.settings.debug,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,22 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from .environment import EngineSettings, load_environment
|
from .environment import (
|
||||||
|
DatabaseSettings,
|
||||||
|
EngineSettings,
|
||||||
|
FlaskSettings,
|
||||||
|
ServerSettings,
|
||||||
|
SocketIOSettings,
|
||||||
|
load_environment,
|
||||||
|
)
|
||||||
from .logging import configure_logging
|
from .logging import configure_logging
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
"DatabaseSettings",
|
||||||
"EngineSettings",
|
"EngineSettings",
|
||||||
|
"FlaskSettings",
|
||||||
"load_environment",
|
"load_environment",
|
||||||
|
"ServerSettings",
|
||||||
|
"SocketIOSettings",
|
||||||
"configure_logging",
|
"configure_logging",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -8,18 +8,47 @@ from pathlib import Path
|
|||||||
from typing import Iterable, Tuple
|
from typing import Iterable, Tuple
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class DatabaseSettings:
|
||||||
|
"""SQLite database configuration for the Engine."""
|
||||||
|
|
||||||
|
path: Path
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class FlaskSettings:
|
||||||
|
"""Parameters that influence Flask application behavior."""
|
||||||
|
|
||||||
|
secret_key: str
|
||||||
|
static_root: Path
|
||||||
|
cors_allowed_origins: Tuple[str, ...]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class SocketIOSettings:
|
||||||
|
"""Configuration for the optional Socket.IO server."""
|
||||||
|
|
||||||
|
cors_allowed_origins: Tuple[str, ...]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class ServerSettings:
|
||||||
|
"""HTTP server binding configuration."""
|
||||||
|
|
||||||
|
host: str
|
||||||
|
port: int
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True, slots=True)
|
@dataclass(frozen=True, slots=True)
|
||||||
class EngineSettings:
|
class EngineSettings:
|
||||||
"""Immutable container describing the Engine runtime configuration."""
|
"""Immutable container describing the Engine runtime configuration."""
|
||||||
|
|
||||||
project_root: Path
|
project_root: Path
|
||||||
database_path: Path
|
|
||||||
static_root: Path
|
|
||||||
cors_allowed_origins: Tuple[str, ...]
|
|
||||||
secret_key: str
|
|
||||||
debug: bool
|
debug: bool
|
||||||
host: str
|
database: DatabaseSettings
|
||||||
port: int
|
flask: FlaskSettings
|
||||||
|
socketio: SocketIOSettings
|
||||||
|
server: ServerSettings
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def logs_root(self) -> Path:
|
def logs_root(self) -> Path:
|
||||||
@@ -27,6 +56,12 @@ class EngineSettings:
|
|||||||
|
|
||||||
return self.project_root / "Logs" / "Server"
|
return self.project_root / "Logs" / "Server"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def database_path(self) -> Path:
|
||||||
|
"""Convenience accessor for the database file path."""
|
||||||
|
|
||||||
|
return self.database.path
|
||||||
|
|
||||||
|
|
||||||
def _resolve_project_root() -> Path:
|
def _resolve_project_root() -> Path:
|
||||||
candidate = os.getenv("BOREALIS_ROOT")
|
candidate = os.getenv("BOREALIS_ROOT")
|
||||||
@@ -61,27 +96,37 @@ def load_environment() -> EngineSettings:
|
|||||||
"""Load Engine settings from environment variables and filesystem hints."""
|
"""Load Engine settings from environment variables and filesystem hints."""
|
||||||
|
|
||||||
project_root = _resolve_project_root()
|
project_root = _resolve_project_root()
|
||||||
database_path = _resolve_database_path(project_root)
|
database = DatabaseSettings(path=_resolve_database_path(project_root))
|
||||||
static_root = _resolve_static_root(project_root)
|
|
||||||
cors_allowed_origins = _parse_origins(os.getenv("BOREALIS_CORS_ALLOWED_ORIGINS"))
|
cors_allowed_origins = _parse_origins(os.getenv("BOREALIS_CORS_ALLOWED_ORIGINS"))
|
||||||
secret_key = os.getenv("BOREALIS_FLASK_SECRET_KEY", "change-me")
|
flask_settings = FlaskSettings(
|
||||||
|
secret_key=os.getenv("BOREALIS_FLASK_SECRET_KEY", "change-me"),
|
||||||
|
static_root=_resolve_static_root(project_root),
|
||||||
|
cors_allowed_origins=cors_allowed_origins,
|
||||||
|
)
|
||||||
|
socket_settings = SocketIOSettings(cors_allowed_origins=cors_allowed_origins)
|
||||||
debug = os.getenv("BOREALIS_DEBUG", "false").lower() in {"1", "true", "yes", "on"}
|
debug = os.getenv("BOREALIS_DEBUG", "false").lower() in {"1", "true", "yes", "on"}
|
||||||
host = os.getenv("BOREALIS_HOST", "127.0.0.1")
|
host = os.getenv("BOREALIS_HOST", "127.0.0.1")
|
||||||
try:
|
try:
|
||||||
port = int(os.getenv("BOREALIS_PORT", "5000"))
|
port = int(os.getenv("BOREALIS_PORT", "5000"))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
port = 5000
|
port = 5000
|
||||||
|
server_settings = ServerSettings(host=host, port=port)
|
||||||
|
|
||||||
return EngineSettings(
|
return EngineSettings(
|
||||||
project_root=project_root,
|
project_root=project_root,
|
||||||
database_path=database_path,
|
|
||||||
static_root=static_root,
|
|
||||||
cors_allowed_origins=cors_allowed_origins,
|
|
||||||
secret_key=secret_key,
|
|
||||||
debug=debug,
|
debug=debug,
|
||||||
host=host,
|
database=database,
|
||||||
port=port,
|
flask=flask_settings,
|
||||||
|
socketio=socket_settings,
|
||||||
|
server=server_settings,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["EngineSettings", "load_environment"]
|
__all__ = [
|
||||||
|
"DatabaseSettings",
|
||||||
|
"EngineSettings",
|
||||||
|
"FlaskSettings",
|
||||||
|
"SocketIOSettings",
|
||||||
|
"ServerSettings",
|
||||||
|
"load_environment",
|
||||||
|
]
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from typing import Optional
|
|||||||
|
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
|
|
||||||
from ...config import EngineSettings
|
from ...config import SocketIOSettings
|
||||||
|
|
||||||
try: # pragma: no cover - import guard
|
try: # pragma: no cover - import guard
|
||||||
from flask_socketio import SocketIO
|
from flask_socketio import SocketIO
|
||||||
@@ -14,7 +14,7 @@ except Exception: # pragma: no cover - optional dependency
|
|||||||
SocketIO = None # type: ignore[assignment]
|
SocketIO = None # type: ignore[assignment]
|
||||||
|
|
||||||
|
|
||||||
def create_socket_server(app: Flask, settings: EngineSettings) -> Optional[SocketIO]:
|
def create_socket_server(app: Flask, settings: SocketIOSettings) -> Optional[SocketIO]:
|
||||||
"""Create a Socket.IO server bound to *app* if dependencies are available."""
|
"""Create a Socket.IO server bound to *app* if dependencies are available."""
|
||||||
|
|
||||||
if SocketIO is None:
|
if SocketIO is None:
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ def _resolve_static_folder(static_root: Path) -> tuple[str | None, str]:
|
|||||||
def create_app(settings: EngineSettings) -> Flask:
|
def create_app(settings: EngineSettings) -> Flask:
|
||||||
"""Create the Flask application instance for the Engine."""
|
"""Create the Flask application instance for the Engine."""
|
||||||
|
|
||||||
static_folder, static_url_path = _resolve_static_folder(settings.static_root)
|
static_folder, static_url_path = _resolve_static_folder(settings.flask.static_root)
|
||||||
app = Flask(
|
app = Flask(
|
||||||
__name__,
|
__name__,
|
||||||
static_folder=static_folder,
|
static_folder=static_folder,
|
||||||
@@ -28,7 +28,7 @@ def create_app(settings: EngineSettings) -> Flask:
|
|||||||
)
|
)
|
||||||
|
|
||||||
app.config.update(
|
app.config.update(
|
||||||
SECRET_KEY=settings.secret_key,
|
SECRET_KEY=settings.flask.secret_key,
|
||||||
JSON_SORT_KEYS=False,
|
JSON_SORT_KEYS=False,
|
||||||
SESSION_COOKIE_HTTPONLY=True,
|
SESSION_COOKIE_HTTPONLY=True,
|
||||||
SESSION_COOKIE_SECURE=not settings.debug,
|
SESSION_COOKIE_SECURE=not settings.debug,
|
||||||
@@ -41,7 +41,7 @@ def create_app(settings: EngineSettings) -> Flask:
|
|||||||
|
|
||||||
CORS(
|
CORS(
|
||||||
app,
|
app,
|
||||||
resources={r"/*": {"origins": list(settings.cors_allowed_origins)}},
|
resources={r"/*": {"origins": list(settings.flask.cors_allowed_origins)}},
|
||||||
supports_credentials=True,
|
supports_credentials=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user