56 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			56 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Python
		
	
	
"""ONVIF util."""
 | 
						|
 | 
						|
from __future__ import annotations
 | 
						|
 | 
						|
from typing import Any
 | 
						|
 | 
						|
from zeep.exceptions import Fault
 | 
						|
 | 
						|
 | 
						|
def extract_subcodes_as_strings(subcodes: Any) -> list[str]:
 | 
						|
    """Stringify ONVIF subcodes."""
 | 
						|
    if isinstance(subcodes, list):
 | 
						|
        return [code.text if hasattr(code, "text") else str(code) for code in subcodes]
 | 
						|
    return [str(subcodes)]
 | 
						|
 | 
						|
 | 
						|
def stringify_onvif_error(error: Exception) -> str:
 | 
						|
    """Stringify ONVIF error."""
 | 
						|
    if isinstance(error, Fault):
 | 
						|
        message = error.message
 | 
						|
        if error.detail is not None:  # checking true is deprecated
 | 
						|
            # Detail may be a bytes object, so we need to convert it to string
 | 
						|
            if isinstance(error.detail, bytes):
 | 
						|
                detail = error.detail.decode("utf-8", "replace")
 | 
						|
            else:
 | 
						|
                detail = str(error.detail)
 | 
						|
            message += ": " + detail
 | 
						|
        if error.code is not None:  # checking true is deprecated
 | 
						|
            message += f" (code:{error.code})"
 | 
						|
        if error.subcodes is not None:  # checking true is deprecated
 | 
						|
            message += (
 | 
						|
                f" (subcodes:{','.join(extract_subcodes_as_strings(error.subcodes))})"
 | 
						|
            )
 | 
						|
        if error.actor:
 | 
						|
            message += f" (actor:{error.actor})"
 | 
						|
    else:
 | 
						|
        message = str(error)
 | 
						|
    return message or f"Device sent empty error with type {type(error)}"
 | 
						|
 | 
						|
 | 
						|
def is_auth_error(error: Exception) -> bool:
 | 
						|
    """Return True if error is an authentication error.
 | 
						|
 | 
						|
    Most of the tested cameras do not return a proper error code when
 | 
						|
    authentication fails, so we need to check the error message as well.
 | 
						|
    """
 | 
						|
    if not isinstance(error, Fault):
 | 
						|
        return False
 | 
						|
    return (
 | 
						|
        any(
 | 
						|
            "NotAuthorized" in code
 | 
						|
            for code in extract_subcodes_as_strings(error.subcodes)
 | 
						|
        )
 | 
						|
        or "auth" in stringify_onvif_error(error).lower()
 | 
						|
    )
 |