CreaRack-SL

Servicio Adapter Registry — Factory de resolución de adapters por vendor

Descripción

Registry centralizado que mapea un slug de vendor a la clase de adapter correspondiente. Resuelve la instancia correcta del adapter para un player digital signage, en función de su fabricante registrado.

Ubicación: signage/services/adapters/registry.py
Funciones públicas:

  • get_adapter(slug, ip, credentials, adapter_config) → SignageDeviceAdapter
  • supports_real_push(slug) → bool
  • register_adapter(slug, adapter_cls) → None (extensibilidad)

Historia de cambios (Hito B)

Antes (fallback silencioso)

  • Mapeo incompleto: solo 4 vendors (spinetix, brightsign, samsung, lg) tenían clase de adapter con push real.
  • Los otros 8 (Crestron, Philips, Barco, Christie, NEC/Sharp + 3 huérfanos) no tenían clase.
  • Cuando se pedía push en un vendor sin adapter, caía automáticamente a GenericSNMP.
  • Problema: GenericSNMP.push_content() devolvía False sin levantar excepción.
  • Efecto: La app reportaba “push soportado” pero el contenido se perdía en silencio (violaba Regla 13 “no fakes”).

Ahora (fallback explícito → ValueError)

  • Mapeo completo y honesto:
    • 7 con push real: spinetix, brightsign, samsung, lg, yodeck, signagelive, iadea
    • 5 monitor-only (sin API de push pública): crestron, philips, barco, christie, nec_sharp → explícitamente resuelven a GenericSNMP
    • 1 genérico: generic_snmp (fallback para endpoints desconocidos con flag push_content: False)
  • Sin fallback silencioso: Si un slug no está registrado, lanza ValueError explícita.
  • Beneficio: Un call-site que pide push a un vendor desconocido falla audiblemente y puede ser capturado/manejado.

Firma pública

def get_adapter(
    slug: str, 
    ip: str, 
    credentials: dict, 
    adapter_config: dict
) -> SignageDeviceAdapter:
    """
    Resolver el adapter correcto por slug de vendor.
    
    Raises:
        ValueError: Si el slug no está registrado.
    """
    ...

def supports_real_push(slug: str) -> bool:
    """
    Retorna True si el vendor tiene un adapter que implementa push real.
    Monitor-only vendors y generic_snmp retornan False.
    """
    ...

def register_adapter(
    slug: str, 
    adapter_cls: type[SignageDeviceAdapter]
) -> None:
    """Registrar un adapter para un vendor slug (extensibilidad)."""
    ...

Mapeo de registros

Real-push adapters (7)

spinetix      → SpinetiXAdapter
brightsign    → BrightSignAdapter
samsung       → SamsungAdapter
lg            → LGAdapter
yodeck        → YodeckAdapter
signagelive   → SignageliveAdapter
iadea         → IAdeaAdapter

Monitor-only vendors (5)

crestron      → GenericSNMPAdapter (SNMP status, no push)
philips       → GenericSNMPAdapter (SNMP status, no push)
barco         → GenericSNMPAdapter (SNMP status, no push)
christie      → GenericSNMPAdapter (SNMP status, no push)
nec_sharp     → GenericSNMPAdapter (SNMP status, no push)

Genéricos

generic_snmp  → GenericSNMPAdapter (fallback explícito)

Constantes internas

_PUSH_SLUGS = frozenset({
    "spinetix", "brightsign", "samsung", "lg", 
    "yodeck", "signagelive", "iadea"
})

_MONITOR_ONLY_SLUGS = frozenset({
    "crestron", "philips", "barco", "christie", "nec_sharp"
})

_REGISTRY: dict[str, type[SignageDeviceAdapter]] = {}

Flujo de get_adapter()

  1. Lazy load: Carga el registro en memoria la primera vez (si no está ya cargado).
  2. Lookup: Busca slug en _REGISTRY.
  3. No encontrado:
    • Antes (fallback): Resolvía a GenericSNMP silenciosamente.
    • Ahora: Lanza ValueError(f"No signage adapter registered for slug '{slug}'. Known slugs: {sorted(_REGISTRY)}").
  4. Encontrado: Instancia adapter_cls(ip, credentials, adapter_config) y retorna.

Flujo de supports_real_push(slug)

  1. Verifica si slug in _PUSH_SLUGS.
  2. Retorna True o False.
  3. Usado por signage/api/players.py para derivar el campo push_implemented en la respuesta de list_adapters().

Impacto en call-sites

Los 4 call-sites que usan get_adapter() ya capturan ValueError:

Call-siteUbicaciónManejo
Deploy Hueysignage/services/deployment_worker.pyTry/except, degrada a noop
Proof-of-play collectorsignage/services/proof_of_play.pyTry/except, logea error
Screenshot takersignage/services/screenshot_worker.pyTry/except, retorna None
Reboot handlersignage/api/display_control.pyTry/except, retorna error

→ Todos ellos ya esperaban que get_adapter() podía fallar y lo manejan gracefully.

Véase también

  • [[feature—signage—hito-b-honestidad-adapters]]
  • [[entity—signage—service—yodeck-adapter]]
  • [[entity—signage—service—signagelive-adapter]]
  • [[entity—signage—service—iadea-adapter]]
  • [[entity—signage—service—generic-snmp-adapter]]
  • [[entity—signage—api—list-adapters]]
  • [[entity—signage—model—signage-vendor-adapter]]