"""Entry point: `cuda-grid-controller --config controller.yaml`.""" from __future__ import annotations import asyncio import logging import sys from pathlib import Path import structlog import typer import uvicorn from .config import Config from .dispatch import CommandDispatcher from .http_api import create_app from .mqtt_loop import MqttLoop from .state import ControllerState cli = typer.Typer(add_completion=False) def _configure_logging(level: str) -> None: logging.basicConfig( format="%(message)s", level=getattr(logging, level.upper(), logging.INFO), ) structlog.configure( processors=[ structlog.processors.add_log_level, structlog.processors.TimeStamper(fmt="iso"), structlog.dev.ConsoleRenderer(), ] ) async def _run(cfg: Config) -> None: state = ControllerState() # Init active_layout = default_layout per instance for inst in cfg.instances: await state.set_layout(inst.name, inst.default_layout) dispatcher = CommandDispatcher(cfg, state) mqtt = MqttLoop(cfg, state, dispatcher.handle) # Wire dispatcher events → MQTT publishes dispatcher.on_state_change = mqtt.publish_state dispatcher.on_event = mqtt.publish_event # HTTP REST app = create_app(cfg, state, dispatcher) server = uvicorn.Server( uvicorn.Config( app, host=cfg.http.host, port=cfg.http.port, log_level=cfg.log.level.lower(), ) ) log = structlog.get_logger() log.info( "controller.starting", instances=[i.name for i in cfg.instances], mqtt=f"{cfg.broker.host}:{cfg.broker.port}", http=f"{cfg.http.host}:{cfg.http.port}", ) try: await asyncio.gather( mqtt.run(), server.serve(), ) except asyncio.CancelledError: log.info("controller.shutdown") finally: await dispatcher.close() await mqtt.stop() @cli.command() def run( config: Path = typer.Option( Path("controller.yaml"), "--config", "-c", help="YAML config path", ), ) -> None: """Запустить controller.""" if not config.exists(): typer.echo(f"config not found: {config}", err=True) raise typer.Exit(1) cfg = Config.from_yaml(config) _configure_logging(cfg.log.level) asyncio.run(_run(cfg)) def main() -> None: cli() if __name__ == "__main__": main()