55import logging
66import ssl
77import urllib .parse
8- from json import JSONDecodeError
98from pathlib import Path
109from types import TracebackType
1110from typing import Any , cast
1413import humps
1514from aiohttp import (
1615 ClientConnectorError ,
17- ClientResponse ,
1816 ClientSession ,
1917 ServerDisconnectedError ,
2018)
2523from pyoverkiz .const import SUPPORTED_SERVERS
2624from pyoverkiz .enums import APIType , CommandMode , Server
2725from pyoverkiz .exceptions import (
28- AccessDeniedToGatewayException ,
29- ActionGroupSetupNotFoundException ,
30- ApplicationNotAllowedException ,
31- BadCredentialsException ,
32- DuplicateActionOnDeviceException ,
3326 ExecutionQueueFullException ,
34- InvalidCommandException ,
3527 InvalidEventListenerIdException ,
36- InvalidTokenException ,
37- MaintenanceException ,
38- MissingAPIKeyException ,
39- MissingAuthorizationTokenException ,
4028 NoRegisteredEventListenerException ,
41- NoSuchResourceException ,
4229 NotAuthenticatedException ,
43- NotSuchTokenException ,
4430 OverkizException ,
45- ServiceUnavailableException ,
46- SessionAndBearerInSameRequestException ,
47- TooManyAttemptsBannedException ,
4831 TooManyConcurrentRequestsException ,
4932 TooManyExecutionsException ,
50- TooManyRequestsException ,
51- UnknownObjectException ,
52- UnknownUserException ,
5333)
5434from pyoverkiz .models import (
5535 Action ,
6949 UIProfileDefinition ,
7050)
7151from pyoverkiz .obfuscate import obfuscate_sensitive_data
52+ from pyoverkiz .response_handler import check_response
7253from pyoverkiz .serializers import prepare_payload
7354from pyoverkiz .types import JSON
7455
@@ -738,7 +719,7 @@ async def _get(self, path: str) -> Any:
738719 headers = headers ,
739720 ssl = self ._ssl ,
740721 ) as response :
741- await self . check_response (response )
722+ await check_response (response )
742723
743724 # 204 has no body.
744725 if response .status == 204 :
@@ -760,10 +741,12 @@ async def _post(
760741 headers = headers ,
761742 ssl = self ._ssl ,
762743 ) as response :
763- await self .check_response (response )
744+ await check_response (response )
745+
764746 # 204 has no body.
765747 if response .status == 204 :
766748 return None
749+
767750 return await response .json ()
768751
769752 async def _delete (self , path : str ) -> None :
@@ -776,125 +759,7 @@ async def _delete(self, path: str) -> None:
776759 headers = headers ,
777760 ssl = self ._ssl ,
778761 ) as response :
779- await self .check_response (response )
780-
781- @staticmethod
782- async def check_response (response : ClientResponse ) -> None :
783- """Check the response returned by the OverKiz API."""
784- if response .status in [200 , 204 ]:
785- return
786-
787- try :
788- result = await response .json (content_type = None )
789- except JSONDecodeError as error :
790- result = await response .text ()
791-
792- if "is down for maintenance" in result :
793- raise MaintenanceException ("Server is down for maintenance" ) from error
794-
795- if response .status == 503 :
796- raise ServiceUnavailableException (result ) from error
797-
798- raise OverkizException (
799- f"Unknown error while requesting { response .url } . { response .status } - { result } "
800- ) from error
801-
802- if result .get ("errorCode" ):
803- # Error messages between cloud and local Overkiz servers can be slightly different
804- # To make it easier to have a strict match for these errors, we remove the double quotes and the period at the end.
805-
806- # An error message can have an empty (None) message
807- message = message .strip ('".' ) if (message := result .get ("error" )) else ""
808-
809- # {"errorCode": "DUPLICATE_FIELD_OR_VALUE", "error": "Another action exists on the same device : rts://1234-5689-1234/123456"}
810- if message .startswith ("Another action exists on the same device" ):
811- raise DuplicateActionOnDeviceException (message )
812-
813- # {"errorCode": "INVALID_FIELD_VALUE", "error": "Unable to determine action group setup (no setup for gateway #1234-5678-1234)"}
814- if message .startswith ("Unable to determine action group setup" ):
815- raise ActionGroupSetupNotFoundException (message )
816-
817- # {"errorCode": "AUTHENTICATION_ERROR", "error": "Too many requests, try again later : login with xxx@xxx.tld"}
818- if "Too many requests" in message :
819- raise TooManyRequestsException (message )
820-
821- # {"errorCode": "AUTHENTICATION_ERROR", "error": "Bad credentials"}
822- if message == "Bad credentials" :
823- raise BadCredentialsException (message )
824-
825- # {"errorCode": "RESOURCE_ACCESS_DENIED", "error": "Not authenticated"}
826- if message == "Not authenticated" :
827- raise NotAuthenticatedException (message )
828-
829- # {"errorCode": "AUTHENTICATION_ERROR", "error": "An API key is required to access this setup"}
830- if message == "An API key is required to access this setup" :
831- raise MissingAPIKeyException (message )
832-
833- # {"error":"Missing authorization token.","errorCode":"RESOURCE_ACCESS_DENIED"}
834- if message == "Missing authorization token" :
835- raise MissingAuthorizationTokenException (message )
836-
837- # {"error": "Server busy, please try again later. (Too many executions)"}
838- if message == "Server busy, please try again later. (Too many executions)" :
839- raise TooManyExecutionsException (message )
840-
841- # {"error": "UNSUPPORTED_OPERATION", "error": "No such command : ..."}
842- if "No such command" in message :
843- raise InvalidCommandException (message )
844-
845- # {"errorCode": "UNSPECIFIED_ERROR", "error": "Invalid event listener id : ..."}
846- if "Invalid event listener id" in message :
847- raise InvalidEventListenerIdException (message )
848-
849- # {"errorCode": "UNSPECIFIED_ERROR", "error": "No registered event listener"}
850- if message == "No registered event listener" :
851- raise NoRegisteredEventListenerException (message )
852-
853- # {"errorCode": "AUTHENTICATION_ERROR", "error": "No such user account : xxxxx"}
854- if "No such user account" in message :
855- raise UnknownUserException (message )
856-
857- # {"errorCode": "INVALID_API_CALL", "error": "No such resource"}
858- if message == "No such resource" :
859- raise NoSuchResourceException (message )
860-
861- # {"errorCode": "RESOURCE_ACCESS_DENIED", "error": "too many concurrent requests"}
862- if message == "too many concurrent requests" :
863- raise TooManyConcurrentRequestsException (message )
864-
865- # {"errorCode": "EXEC_QUEUE_FULL", "error": "Execution queue is full on gateway: #xxx-yyyy-zzzz (soft limit: 10)"}
866- if "Execution queue is full on gateway" in message :
867- raise ExecutionQueueFullException (message )
868-
869- if message == "Cannot use JSESSIONID and bearer token in same request" :
870- raise SessionAndBearerInSameRequestException (message )
871-
872- if message == "Too many attempts with an invalid token, temporarily banned" :
873- raise TooManyAttemptsBannedException (message )
874-
875- if "Invalid token : " in message :
876- raise InvalidTokenException (message )
877-
878- if "Not such token with UUID: " in message :
879- raise NotSuchTokenException (message )
880-
881- if "Unknown user :" in message :
882- raise UnknownUserException (message )
883-
884- # {"error":"Unknown object.","errorCode":"UNSPECIFIED_ERROR"}
885- if message == "Unknown object" :
886- raise UnknownObjectException (message )
887-
888- # {"errorCode": "RESOURCE_ACCESS_DENIED", "error": "Access denied to gateway #1234-5678-1234 for action ADD_TOKEN"}
889- if "Access denied to gateway" in message :
890- raise AccessDeniedToGatewayException (message )
891-
892- # {"errorCode": "RESOURCE_ACCESS_DENIED", "error": "Your setup cannot be accessed through this application"}
893- if message == "Your setup cannot be accessed through this application" :
894- raise ApplicationNotAllowedException (message )
895-
896- # Undefined Overkiz exception
897- raise OverkizException (result )
762+ await check_response (response )
898763
899764 async def _refresh_token_if_expired (self ) -> None :
900765 """Check if token is expired and request a new one."""
0 commit comments