diff --git a/backend/src/utilities/ndpi_classifier.py b/backend/src/utilities/ndpi_classifier.py index f161058..e90c6c7 100644 --- a/backend/src/utilities/ndpi_classifier.py +++ b/backend/src/utilities/ndpi_classifier.py @@ -8,6 +8,7 @@ This module keeps nDPI integration optional: from __future__ import annotations import logging +import importlib import time from dataclasses import dataclass from typing import Any, Dict, Optional, Tuple @@ -16,10 +17,14 @@ from scapy.all import IP, IPv6, TCP, UDP # type: ignore logger = logging.getLogger("ndpi_classifier") -try: - import ndpi # type: ignore -except Exception: # pragma: no cover - optional dependency - ndpi = None +ndpi = None # type: ignore +_ndpi_import_error: Optional[str] = None +for _module_name in ("ndpi", "pyndpi"): + try: # pragma: no cover - import depends on host runtime + ndpi = importlib.import_module(_module_name) # type: ignore + break + except Exception as exc: + _ndpi_import_error = f"{_module_name}: {exc!r}" def _is_jsonable_scalar(value: Any) -> bool: @@ -63,13 +68,21 @@ class NDPIClassifier: self._initialized = True if ndpi is None: - logger.warning("nDPI Python bindings not installed; DPI enrichment disabled") + logger.warning( + "nDPI Python bindings unavailable; DPI enrichment disabled (%s)", + _ndpi_import_error or "no ndpi module found", + ) return try: engine_cls = getattr(ndpi, "NDPI", None) if engine_cls is None: - logger.warning("nDPI bindings found but NDPI class missing; DPI enrichment disabled") + exported = [name for name in dir(ndpi) if name.lower().startswith("ndpi")] + logger.warning( + "nDPI bindings imported but NDPI class missing (module=%s, ndpi* exports=%s); DPI enrichment disabled", + getattr(ndpi, "__name__", "unknown"), + exported[:20], + ) return self._engine = engine_cls() logger.info("nDPI classifier initialized") diff --git a/setup_build_server.sh b/setup_build_server.sh index 2adeb73..93fde5e 100755 --- a/setup_build_server.sh +++ b/setup_build_server.sh @@ -88,6 +88,25 @@ if [ -d "/tmp/nDPI/python" ]; then pip install "setuptools<81" "packaging<25" wheel if ! pip install --no-build-isolation /tmp/nDPI/python; then echo "==> WARNING: nDPI Python bindings install failed, backend will run without DPI enrichment" + else + if python - <<'PY' +import importlib +mods = [] +for name in ("ndpi", "pyndpi"): + try: + m = importlib.import_module(name) + mods.append((name, getattr(m, "__file__", "unknown"))) + except Exception: + pass +if not mods: + raise SystemExit(1) +print("nDPI Python modules:", mods) +PY + then + echo "==> nDPI Python import check passed" + else + echo "==> WARNING: nDPI installed but import failed in backend venv" + fi fi fi @@ -234,6 +253,18 @@ if [ -d "/tmp/nDPI/python" ]; then pip install "setuptools<81" "packaging<25" wheel if ! pip install --no-build-isolation /tmp/nDPI/python; then echo "WARNING: nDPI Python bindings install failed during runner build" + else + python - <<'PY' || echo "WARNING: nDPI import check failed during runner build" +import importlib +for name in ("ndpi", "pyndpi"): + try: + m = importlib.import_module(name) + print("nDPI import OK:", name, getattr(m, "__file__", "unknown")) + raise SystemExit(0) + except Exception: + pass +raise SystemExit(1) +PY fi fi pip install -r requirements.txt