utp_service/backend/app/services/discovery/uri.py
2026-04-13 16:17:09 +03:00

68 lines
2.3 KiB
Python

"""
URI parsing and device classification utilities.
All functions are pure (no I/O, no DB).
"""
import re
from urllib.parse import urlparse
_SERIAL_SCHEMES = {"serial", "com"}
_SERVICE_HOSTS = {"localhost", "127.0.0.1"}
# Plugin name prefixes whose URIs point at the CAPS server itself, not separate devices.
_SKIP_PLUGIN_PREFIXES = ("mnemo", "processor", "recognition", "photo", "voice")
def extract_device_info(uri: str) -> tuple[str, str, str] | None:
"""Return (ip, username, password) from a URI, or None if not a network device.
Username and password are extracted from URI credentials (http://user:pass@ip).
They may be empty strings if not present in the URI.
"""
if not uri:
return None
try:
parsed = urlparse(uri)
scheme = (parsed.scheme or "").lower()
if scheme in _SERIAL_SCHEMES:
return None
hostname = parsed.hostname
if not hostname or hostname in _SERVICE_HOSTS:
return None
if re.match(r"^\d{1,3}(\.\d{1,3}){3}$", hostname):
return hostname, parsed.username or "", parsed.password or ""
except Exception:
pass
return None
def extract_ip(uri: str) -> str | None:
"""Return IP from a URI string, or None if not a network device."""
info = extract_device_info(uri)
return info[0] if info else None
def cls_to_category(cls: str) -> str:
cls_lower = cls.lower()
if "camera" in cls_lower or "facedetect" in cls_lower:
return "camera"
if "controller" in cls_lower or "ovenmk" in cls_lower or "rodos" in cls_lower:
return "io_board"
if "payment" in cls_lower or "sberpilot" in cls_lower or "payx" in cls_lower:
return "bank_terminal"
if "payonline" in cls_lower or "kkt" in cls_lower or "fiscal" in cls_lower:
return "cash_register"
return "other"
def cls_to_role(cls: str, plugin_name: str) -> str:
cls_lower = cls.lower()
name_lower = plugin_name.lower()
if "camera" in cls_lower or "camera" in name_lower:
if "grz" in name_lower or "plate" in name_lower or "lpr" in name_lower or "frame" in name_lower:
return "plate"
if "face" in name_lower or "lico" in name_lower:
return "face"
return "overview"
return "other"