Files
photoBooth/main.py
T
admin 9a006f1457
🚀 Deploy — JH Photomaton / 🔍 Vérification (push) Has been cancelled
🚀 Deploy — JH Photomaton / 🍓 Deploy sur le Pi (push) Has been cancelled
all
2026-07-17 00:44:22 +02:00

162 lines
5.0 KiB
Python

"""JH Photomaton -- Interface de gestion (Les Sapins Du Web)."""
import asyncio
import logging
from contextlib import asynccontextmanager
from pathlib import Path
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.staticfiles import StaticFiles
from starlette.middleware.sessions import SessionMiddleware
from backend.services.config_service import ConfigService
from backend.services.event_service import EventService
from backend.services.led_service import LEDService
from backend.services.button_service import ButtonService
from backend.services.photobooth_service import PhotoboothService
from backend.services.printer_service import PrinterService
from backend.services.system_service import SystemService
from backend.utils.ws_manager import WSManager
from backend.api import (
gallery,
admin_api,
admin_gallery_api,
leds_api,
system_api,
print_api,
actions_api,
webhooks,
event_api,
)
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
)
logger = logging.getLogger(__name__)
BASE_DIR = Path(__file__).parent
@asynccontextmanager
async def lifespan(app: FastAPI):
config_svc = ConfigService(BASE_DIR / "config" / "settings.yaml")
config = config_svc.load()
ws_manager = WSManager()
photobooth_svc = PhotoboothService(config)
system_svc = SystemService()
printer_svc = PrinterService(config)
event_svc = EventService()
await printer_svc.init_db(BASE_DIR / "data" / "print_queue.db")
await event_svc.init_db(BASE_DIR / "data" / "events.db")
from datetime import datetime as _dt
ev = config.event
if not ev.started_at:
ev.started_at = _dt.now().timestamp()
await event_svc.ensure_event(ev.slug, ev.name, ev.started_at)
led_svc = LEDService(config)
led_svc.start()
loop = asyncio.get_event_loop()
led_svc.set_loop(loop)
led_svc.set_on_change(ws_manager.broadcast)
button_svc = ButtonService(config, led_svc, photobooth_svc, ws_manager, loop)
button_svc.start()
app.state.config = config
app.state.config_service = config_svc
app.state.ws_manager = ws_manager
app.state.led_service = led_svc
app.state.button_service = button_svc
app.state.photobooth_service = photobooth_svc
app.state.printer_service = printer_svc
app.state.system_service = system_svc
app.state.event_service = event_svc
stats_task = asyncio.create_task(_system_stats_loop(system_svc, ws_manager))
logger.info("JH Photomaton demarre -- port %d", config.app.port)
led_svc.play("idle")
yield
stats_task.cancel()
button_svc.stop()
led_svc.stop()
await photobooth_svc.close()
await printer_svc.close()
await event_svc.close()
logger.info("JH Photomaton arrete")
async def _system_stats_loop(sys_svc: SystemService, ws: WSManager):
while True:
try:
stats = sys_svc.get_stats()
await ws.broadcast({"type": "system_stats", "data": stats})
except Exception as e:
logger.debug("Stats loop: %s", e)
await asyncio.sleep(5)
app = FastAPI(
title="JH Photomaton",
description="Interface de gestion du photomaton -- Les Sapins Du Web",
version="1.0.0",
lifespan=lifespan,
)
app.add_middleware(
SessionMiddleware,
secret_key="jh-photomaton-session-2026",
max_age=86400,
)
app.mount("/static", StaticFiles(directory=BASE_DIR / "frontend" / "static"), name="static")
app.include_router(gallery.router)
app.include_router(admin_api.router)
app.include_router(admin_gallery_api.router)
app.include_router(leds_api.router, prefix="/api")
app.include_router(system_api.router, prefix="/api")
app.include_router(print_api.router, prefix="/api")
app.include_router(actions_api.router, prefix="/api")
app.include_router(webhooks.router, prefix="/api")
app.include_router(event_api.router, prefix="/api")
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
ws_manager: WSManager = websocket.app.state.ws_manager
await ws_manager.connect(websocket)
try:
led = websocket.app.state.led_service
sys_svc = websocket.app.state.system_service
await ws_manager.send(websocket, {"type": "connected", "led_effect": led.current_effect})
await ws_manager.send(websocket, {"type": "system_stats", "data": sys_svc.get_stats()})
except Exception:
pass
try:
while True:
data = await websocket.receive_text()
import json
try:
msg = json.loads(data)
if msg.get("type") == "ping":
await ws_manager.send(websocket, {"type": "pong"})
except Exception:
pass
except WebSocketDisconnect:
ws_manager.disconnect(websocket)
if __name__ == "__main__":
import uvicorn
cfg = ConfigService(BASE_DIR / "config" / "settings.yaml").load()
uvicorn.run("main:app", host=cfg.app.host, port=cfg.app.port, reload=cfg.app.debug, log_level="info")