CreaRack-SL

Task Huey: Conversión asíncrona .vsdx/.vsd → SVG

Descripción

Módulo: racks/tasks.py

Task Huey asíncrona que convierte ficheros Visio modernos (.vsdx, .vsd) a imágenes vectoriales SVG, ejecutada en el worker para no bloquear el request principal. Diseñada para stencils de fabricante grandes (Cisco, APC, Schneider).

Decorador

@db_task()
def convert_visio_async(session_id: str, filepath: str) → None
  • Parámetro session_id: UUID único de la sesión (mismo que en analyze), identifica el directorio temporal de trabajo
  • Parámetro filepath: ruta absoluta al fichero .vsdx/.vsd ya guardado en disco
  • Contexto DB: decorador @db_task() permite acceso a ORM si fuera necesario (ahora no lo usa, pero el estado vive en JSON transitorio)

Flujo de ejecución

  1. Obtiene directorio temporal: MEDIA_ROOT/temp/{session_id}
  2. Carga libvisio-ng (lazy, solo en worker — GPL-3.0):
    • Intenta libvisio_ng.get_page_info(filepath) para obtener nombres de páginas (fallback: nombres de fichero)
    • Llamadas: libvisio_ng.convert(filepath, output_dir=temp_dir)
  3. Genera SVG por página: v1 granularidad página (un dibujo con shapes agrupados → un SVG único; troceo por shape individual es v2)
  4. Sanitiza cada SVG antes de quedar disponible (sanitize_svg_file())
  5. Escribe manifest de masters: lista de {“name”, “u_height”, “image_path”} en el estado de la sesión
  6. Persiste estado final: status=done o status=error

Funciones auxiliares

write_session_state(session_id: str, status: str, masters=None, error="")

Escribe estado JSON a temp/{session_id}/visio_session.json.

Estados:

  • processing — conversión en marcha (escrito inmediatamente por analyze)
  • done — conversión exitosa, masters listo para confirm
  • error — conversión fallida, con mensaje en error

Payload JSON:

{
  "status": "done",
  "masters": [
    {"name": "Cisco Rack Layout", "u_height": 1, "image_path": "uploads/temp/{sid}/page1.svg"},
    {"name": "APC PDUs", "u_height": 1, "image_path": "uploads/temp/{sid}/page2.svg"}
  ],
  "error": ""
}

read_session_state(session_id: str) → dict | None

Lee el estado JSON. Devuelve None si no existe (sesión expirada o inválida).

Estrategia de nombres y rutas

  • Nombres de páginas: libvisio_ng.get_page_info() devuelve lista de objetos/dicts con name; se usan si están disponibles, fallback a nombres de fichero generados por la conversión (ej. page1, page2)
  • Rutas relativas: todos los image_path son relativos a MEDIA_ROOT (formato uploads/temp/{sid}/page.svg) para facilitar persistencia posterior en confirm

Ciclo de vida

  1. Antes: análisis del fichero (extensión, tamaño) en analyze; sesión creada, UUID generado, estado = processing
  2. Durante: task corre en worker Huey; frontend hace polling a GET /visio/session/{id}
  3. Después: estado done → frontend obtiene lista de masters → usuario confirma en confirm
  4. Limpieza: temp/{sid} se elimina tras éxito de confirm o expiración (TTL configurable, no en este PR)

Manejo de errores

  • libvisio_ng no instalado: estado = error, error="Visio converter not installed on this server"
  • Conversión fallida: estado = error + mensaje de excepción
  • Ningún SVG convertible: estado = error, error="No convertible shapes found in the file"
  • SVG generado inválido (sanitización): fichero eliminado, no entra en manifest (logging a WARN)

Testing

Cubierto en tests/api/test_visio_import_v2.py:

  • Stub de libvisio_ng: mock convert() y get_page_info() con payload malicioso para verificar sanitización post-conversión
  • Huey immediate mode: task se ejecuta sincronamente en tests
  • Validación de nombres: nombres de páginas de get_page_info() aparecen en masters o fallback a nombres de fichero
  • Escenarios de error: sessions 404, conversión fallida, oversized upload

Dependencia

  • libvisio-ng 0.6.1 — Python puro, wheel universal, GPL-3.0, instalada via requirements; solo en worker Huey, no en base Django

Véase también

  • [[feature—racks—import-visio-v2]]
  • [[entity—racks—service—svg-sanitizer]]
  • [[entity—racks—endpoint—visio-session-status]]
  • [[entity—racks—endpoint—visio-analyze]]