163 lines
5.8 KiB
Python
163 lines
5.8 KiB
Python
"""API gestion de la file d'attente d'impression."""
|
|
|
|
import asyncio
|
|
import logging
|
|
from pathlib import Path
|
|
|
|
from fastapi import APIRouter, Request, Query
|
|
from fastapi.responses import JSONResponse
|
|
|
|
logger = logging.getLogger(__name__)
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/print/request")
|
|
async def print_request(
|
|
request: Request,
|
|
filename: str = Query(..., description="Chemin absolu du fichier à imprimer"),
|
|
copies: int = Query(default=1, ge=1, le=3),
|
|
):
|
|
"""
|
|
Reçoit la demande d'impression depuis photobooth-app
|
|
(appelé par le share_command 'Demande d'impression').
|
|
"""
|
|
printer_svc = request.app.state.printer_service
|
|
pb = request.app.state.photobooth_service
|
|
led = request.app.state.led_service
|
|
ws = request.app.state.ws_manager
|
|
|
|
# Construit l'URL de miniature depuis le filename
|
|
stem = Path(filename).stem
|
|
thumb_url = pb.thumbnail_url(stem)
|
|
|
|
entry = await printer_svc.add_request(filename, thumb_url, copies)
|
|
|
|
await ws.broadcast({"type": "print_request", "entry": entry})
|
|
|
|
# Compteur statistiques événement
|
|
event_svc = getattr(request.app.state, "event_service", None)
|
|
if event_svc:
|
|
slug = request.app.state.config.event.slug
|
|
asyncio.create_task(event_svc.increment(slug, "print_requests"))
|
|
|
|
# Feedback LED si impression directe
|
|
if request.app.state.config.print.mode == "direct":
|
|
led.play("printing")
|
|
|
|
logger.info("Demande impression reçue: %s", filename)
|
|
return {"ok": True, "id": entry["id"], "mode": request.app.state.config.print.mode}
|
|
|
|
|
|
@router.get("/print/queue")
|
|
async def get_queue(
|
|
request: Request,
|
|
status: str | None = Query(default=None),
|
|
):
|
|
"""Retourne la file d'attente d'impression."""
|
|
printer_svc = request.app.state.printer_service
|
|
queue = await printer_svc.get_queue(status)
|
|
printers = await printer_svc.get_printers_status()
|
|
return {"queue": queue, "printers": printers}
|
|
|
|
|
|
@router.post("/print/execute/{entry_id}")
|
|
async def execute_print(
|
|
request: Request,
|
|
entry_id: str,
|
|
copies: int = Query(default=1, ge=1, le=3),
|
|
):
|
|
"""Lance l'impression d'une entrée en attente (validation admin)."""
|
|
printer_svc = request.app.state.printer_service
|
|
led = request.app.state.led_service
|
|
ws = request.app.state.ws_manager
|
|
|
|
led.play("printing")
|
|
result = await printer_svc.execute_print(entry_id, copies)
|
|
|
|
await ws.broadcast({"type": "print_result", "entry_id": entry_id, "result": result})
|
|
|
|
if result["success"]:
|
|
led.play("finished")
|
|
event_svc = getattr(request.app.state, "event_service", None)
|
|
if event_svc:
|
|
slug = request.app.state.config.event.slug
|
|
asyncio.create_task(event_svc.increment(slug, "prints_done"))
|
|
else:
|
|
led.play("error")
|
|
|
|
return result
|
|
|
|
|
|
@router.post("/print/cancel/{entry_id}")
|
|
async def cancel_print(request: Request, entry_id: str):
|
|
"""Annule une demande en attente."""
|
|
printer_svc = request.app.state.printer_service
|
|
ws = request.app.state.ws_manager
|
|
ok = await printer_svc.cancel(entry_id)
|
|
if ok:
|
|
await ws.broadcast({"type": "print_cancelled", "entry_id": entry_id})
|
|
return {"ok": ok}
|
|
|
|
|
|
@router.post("/print/cups/cancel/{printer_name}")
|
|
async def cancel_cups_jobs(request: Request, printer_name: str):
|
|
"""Annule tous les jobs CUPS d'une imprimante."""
|
|
printer_svc = request.app.state.printer_service
|
|
ok = await printer_svc.cancel_cups_jobs(printer_name)
|
|
return {"ok": ok, "printer": printer_name}
|
|
|
|
|
|
@router.get("/print/printers")
|
|
async def get_printers(request: Request):
|
|
"""Statut des imprimantes CUPS."""
|
|
printer_svc = request.app.state.printer_service
|
|
return await printer_svc.get_printers_status()
|
|
|
|
|
|
@router.post("/print/mode")
|
|
async def set_print_mode(request: Request, mode: str = Query(...)):
|
|
"""Change le mode d'impression (direct | validation | gallery)."""
|
|
if mode not in ("direct", "validation", "gallery"):
|
|
return JSONResponse({"error": "Mode invalide"}, status_code=400)
|
|
config_svc = request.app.state.config_service
|
|
config_svc.save_print_mode(mode)
|
|
request.app.state.config.print.mode = mode
|
|
return {"ok": True, "mode": mode}
|
|
|
|
|
|
# ── Gestion avancée des imprimantes CUPS ──────────────────────────────────────
|
|
|
|
@router.post("/print/printers/{printer_name}/enable")
|
|
async def printer_enable(request: Request, printer_name: str):
|
|
"""Active une imprimante CUPS (cupsenable + cupsaccept)."""
|
|
ok = await request.app.state.printer_service.enable_printer(printer_name)
|
|
return {"ok": ok, "printer": printer_name, "action": "enable"}
|
|
|
|
|
|
@router.post("/print/printers/{printer_name}/disable")
|
|
async def printer_disable(request: Request, printer_name: str):
|
|
"""Désactive une imprimante CUPS (cupsdisable)."""
|
|
ok = await request.app.state.printer_service.disable_printer(printer_name)
|
|
return {"ok": ok, "printer": printer_name, "action": "disable"}
|
|
|
|
|
|
@router.post("/print/printers/{printer_name}/reject")
|
|
async def printer_reject(request: Request, printer_name: str):
|
|
"""Refuse les nouveaux jobs sans stopper l'impression en cours."""
|
|
ok = await request.app.state.printer_service.reject_jobs(printer_name)
|
|
return {"ok": ok, "printer": printer_name, "action": "reject"}
|
|
|
|
|
|
@router.get("/print/printers/{printer_name}/jobs")
|
|
async def printer_jobs(request: Request, printer_name: str):
|
|
"""Liste les jobs CUPS en cours pour une imprimante."""
|
|
jobs = await request.app.state.printer_service.get_cups_jobs(printer_name)
|
|
return {"printer": printer_name, "jobs": jobs}
|
|
|
|
|
|
@router.delete("/print/printers/jobs/{job_id}")
|
|
async def cancel_one_job(request: Request, job_id: str):
|
|
"""Annule un job CUPS précis par son ID."""
|
|
ok = await request.app.state.printer_service.cancel_cups_job(job_id)
|
|
return {"ok": ok, "job_id": job_id}
|