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/.vsdya 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
- Obtiene directorio temporal:
MEDIA_ROOT/temp/{session_id} - 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)
- Intenta
- Genera SVG por página: v1 granularidad página (un dibujo con shapes agrupados → un SVG único; troceo por shape individual es v2)
- Sanitiza cada SVG antes de quedar disponible (
sanitize_svg_file()) - Escribe manifest de masters: lista de {“name”, “u_height”, “image_path”} en el estado de la sesión
- Persiste estado final:
status=doneostatus=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 confirmerror— conversión fallida, con mensaje enerror
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 conname; se usan si están disponibles, fallback a nombres de fichero generados por la conversión (ej.page1,page2) - Rutas relativas: todos los
image_pathson relativos aMEDIA_ROOT(formatouploads/temp/{sid}/page.svg) para facilitar persistencia posterior en confirm
Ciclo de vida
- Antes: análisis del fichero (extensión, tamaño) en
analyze; sesión creada, UUID generado, estado =processing - Durante: task corre en worker Huey; frontend hace polling a
GET /visio/session/{id} - Después: estado
done→ frontend obtiene lista de masters → usuario confirma enconfirm - Limpieza:
temp/{sid}se elimina tras éxito de confirm o expiración (TTL configurable, no en este PR)
Manejo de errores
libvisio_ngno 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()yget_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]]