From 0e150331b41710a720460d2af2c9cffacf18d567 Mon Sep 17 00:00:00 2001 From: Mark Cotton Date: Mon, 24 Jul 2023 10:24:44 -0600 Subject: [PATCH] Added timeout parameter to Reqeusts calls, making it user adjustable. Added some more exception handling. Bumping version to 0.0.5 --- src/EagleEyev3/__init__.py | 253 ++++++++++++++++++++++++++++++------- 1 file changed, 209 insertions(+), 44 deletions(-) diff --git a/src/EagleEyev3/__init__.py b/src/EagleEyev3/__init__.py index f8be291..75252d9 100644 --- a/src/EagleEyev3/__init__.py +++ b/src/EagleEyev3/__init__.py @@ -1,5 +1,5 @@ """ Python client for Eagle Eye Networks APIv3 """ -__version__ = "0.0.4" +__version__ = "0.0.5" import json @@ -21,7 +21,7 @@ class EagleEyev3(): Class representing the EagleEyev3 client. """ - __version__ = "0.0.4" + __version__ = "0.0.5" __all__ = ['EagleEyev3', 'Device', 'Camera'] def __init__(self, config=None): @@ -61,6 +61,18 @@ class EagleEyev3(): except FileNotFoundError as e: logging.warn("self.lazy_login is set to {self.lazy_login} but could not find .lazy_login file to load") + # for use with request calls, can be an int, tuple, or None + # preferred would be a tuple with the first value is time to connect, second is time to first byte + # https://requests.readthedocs.io/en/latest/user/advanced/#timeouts + # called by self._get_timeout_values + self.timeout_values = { + 'default': (3,5), + 'login': (5, 30), + 'logout': (5, 15), + 'list_of_events': (6, 20), + 'live_preview': (3, 5) + } + def _load_vars_from_settings(self, config={}): """ Load variables from the settings module. @@ -77,7 +89,6 @@ class EagleEyev3(): self.redirect_uri = f"{self.server_protocol}://{self.server_host}:{self.server_port}/{self.server_path}" - def _save_access_token(self): with open(".lazy_login", "w") as json_file: json.dump({ @@ -96,11 +107,9 @@ class EagleEyev3(): self.get_base_url(cascade=True) - def time_now(self): return datetime.now(tz=self.user_tz_obj).isoformat(timespec='milliseconds') - def time_before(self, ts=None, hours=6): if ts == None: ts = datetime.now(tz=self.user_tz_obj) @@ -110,8 +119,6 @@ class EagleEyev3(): return (ts - timedelta(hours=hours)).isoformat(timespec='milliseconds') - - def login_tokens(self, code=None, cascade=True): """ Obtains login tokens using the authorization code. @@ -128,7 +135,7 @@ class EagleEyev3(): url = baseUrl + pathUrl # Send a POST request to obtain login tokens - response = requests.post(url, auth=(self.client_id, self.client_secret)) + response = requests.post(url, auth=(self.client_id, self.client_secret), timeout=self._get_timeout_values('login')) response_json = response.json() logging.info(f"{response.status_code} in login_tokens") @@ -174,7 +181,7 @@ class EagleEyev3(): } # Send a POST request to obtain the base URL - response = requests.post(url, json=payload, headers=headers) + response = requests.post(url, json=payload, headers=headers, timeout=self._get_timeout_values('logout')) response_json = response.json() logging.info(f"{response.status_code} in logout") @@ -210,11 +217,28 @@ class EagleEyev3(): "Accept": "application/json" } - # Send a GET request to obtain the base URL - response = requests.get(url, headers=headers) - response_json = response.json() + try: + # Send a GET request to obtain the base URL + response = requests.get(url, headers=headers, timeout=self._get_timeout_values('base_url')) + response_json = response.json() - logging.info(f"{response.status_code} in get_base_url") + logging.info(f"{response.status_code} in get_base_url") + + except requests.exceptions.Timeout: + logging.warn(f"timeout expired for {self.id} get_base_url()") + return { + "success": False, + "response_http_status": 0, + "data": None + } + + except requests.exceptions.RequestException as e: + logging.warn(e) + return { + "success": False, + "response_http_status": 0, + "data": None + } if response.status_code == 200: success = True @@ -244,11 +268,28 @@ class EagleEyev3(): "Accept": "application/json" } - # Send a GET request to obtain the current user information - response = requests.get(url, headers=headers) - response_json = response.json() + try: + # Send a GET request to obtain the current user information + response = requests.get(url, headers=headers, timeout=self._get_timeout_values('curent_user')) + response_json = response.json() - logging.info(f"{response.status_code} in get_current_user") + logging.info(f"{response.status_code} in get_current_user") + + except requests.exceptions.Timeout: + logging.warn(f"timeout expired for {self.id} get_current_user()") + return { + "success": False, + "response_http_status": 0, + "data": None + } + + except requests.exceptions.RequestException as e: + logging.warn(e) + return { + "success": False, + "response_http_status": 0, + "data": None + } if response.status_code == 200: success = True @@ -276,10 +317,27 @@ class EagleEyev3(): "Accept": "application/json" } - response = requests.get(url, headers=headers) - response_json = response.json() + try: + response = requests.get(url, headers=headers, timeout=self._get_timeout_values('list_of_users')) + response_json = response.json() - logging.info(f"{response.status_code} in get_list_of_users") + logging.info(f"{response.status_code} in get_list_of_users") + + except requests.exceptions.Timeout: + logging.warn(f"timeout expired for {self.id} get_list_of_users()") + return { + "success": False, + "response_http_status": 0, + "data": None + } + + except requests.exceptions.RequestException as e: + logging.warn(e) + return { + "success": False, + "response_http_status": 0, + "data": None + } if response.status_code == 200: success = True @@ -306,10 +364,27 @@ class EagleEyev3(): "Accept": "application/json" } - response = requests.get(url, headers=headers) - response_json = response.json() + try: + response = requests.get(url, headers=headers, timeout=self._get_timeout_values('list_of_cameras')) + response_json = response.json() - logging.info(f"{response.status_code} in get_list_of_cameras") + logging.info(f"{response.status_code} in get_list_of_cameras") + + except requests.exceptions.Timeout: + logging.warn(f"timeout expired for {self.id} get_list_of_cameras()") + return { + "success": False, + "response_http_status": 0, + "data": None + } + + except requests.exceptions.RequestException as e: + logging.warn(e) + return { + "success": False, + "response_http_status": 0, + "data": None + } if response.status_code == 200: success = True @@ -346,10 +421,27 @@ class EagleEyev3(): "Accept": "application/json" } - response = requests.get(url, headers=headers) - response_json = response.json() + try: + response = requests.get(url, headers=headers, timeout=self._get_timeout_values('list_of_bridges')) + response_json = response.json() - logging.info(f"{response.status_code} in get_list_of_bridges") + logging.info(f"{response.status_code} in get_list_of_bridges") + + except requests.exceptions.Timeout: + logging.warn(f"timeout expired for {self.id} get_list_of_bridges()") + return { + "success": False, + "response_http_status": 0, + "data": None + } + + except requests.exceptions.RequestException as e: + logging.warn(e) + return { + "success": False, + "response_http_status": 0, + "data": None + } if response.status_code == 200: success = True @@ -376,10 +468,27 @@ class EagleEyev3(): "Accept": "application/json" } - response = requests.get(url, headers=headers) - response_json = response.json() + try: + response = requests.get(url, headers=headers, timeout=self._get_timeout_values('list_of_switches')) + response_json = response.json() - logging.info(f"{response.status_code} in get_list_of_switches") + logging.info(f"{response.status_code} in get_list_of_switches") + + except requests.exceptions.Timeout: + logging.warn(f"timeout expired for {self.id} get_list_of_switches()") + return { + "success": False, + "response_http_status": 0, + "data": None + } + + except requests.exceptions.RequestException as e: + logging.warn(e) + return { + "success": False, + "response_http_status": 0, + "data": None + } if response.status_code == 200: success = True @@ -406,10 +515,27 @@ class EagleEyev3(): "Accept": "application/json" } - response = requests.get(url, headers=headers) - response_json = response.json() + try: + response = requests.get(url, headers=headers, timeout=self._get_timeout_values('list_of_available_devices')) + response_json = response.json() - logging.info(f"{response.status_code} in get_list_of_available_devices") + logging.info(f"{response.status_code} in get_list_of_available_devices") + + except requests.exceptions.Timeout: + logging.warn(f"timeout expired for {self.id} get_list_of_available_devices()") + return { + "success": False, + "response_http_status": 0, + "data": None + } + + except requests.exceptions.RequestException as e: + logging.warn(e) + return { + "success": False, + "response_http_status": 0, + "data": None + } if response.status_code == 200: success = True @@ -435,10 +561,27 @@ class EagleEyev3(): "Accept": "application/json" } - response = requests.get(url, headers=headers) - response_json = response.json() + try: + response = requests.get(url, headers=headers, timeout=self._get_timeout_values('list_of_multi_cameras')) + response_json = response.json() - logging.info(f"{response.status_code} in get_list_of_multi_cameras") + logging.info(f"{response.status_code} in get_list_of_multi_cameras") + + except requests.exceptions.Timeout: + logging.warn(f"timeout expired for {self.id} get_list_of_multi_cameras()") + return { + "success": False, + "response_http_status": 0, + "data": None + } + + except requests.exceptions.RequestException as e: + logging.warn(e) + return { + "success": False, + "response_http_status": 0, + "data": None + } if response.status_code == 200: success = True @@ -464,10 +607,27 @@ class EagleEyev3(): "Accept": "application/json" } - response = requests.get(url, headers=headers) - response_json = response.json() + try: + response = requests.get(url, headers=headers, timeout=self._get_timeout_values('list_of_feeds')) + response_json = response.json() - logging.info(f"{response.status_code} in get_list_of_feeds") + logging.info(f"{response.status_code} in get_list_of_feeds") + + except requests.exceptions.Timeout: + logging.warn(f"timeout expired for {self.id} get_list_of_feeds()") + return { + "success": False, + "response_http_status": 0, + "data": None + } + + except requests.exceptions.RequestException as e: + logging.warn(e) + return { + "success": False, + "response_http_status": 0, + "data": None + } if response.status_code == 200: success = True @@ -480,7 +640,6 @@ class EagleEyev3(): "data": response_json } - def get_camera_by_id(self, esn): found_camera = None for camera in self.cameras: @@ -494,12 +653,17 @@ class EagleEyev3(): logging.debug(f"returning camera {camera} for search query {esn}") return camera + def _get_timeout_values(self, name='default'): + if name in self.timeout_values: + return self.timeout_values[name] + else: + return self.timeout_values['default'] class Device(): - def __init__(self, id=None, name=None, status=None, account_id=None, user_base_url=None, een_instance=None): + def __init__(self, id=None, name=None, status=dict(), account_id=None, user_base_url=None, een_instance=None): self.id = id self.name = name @@ -541,7 +705,7 @@ class Device(): class Camera(Device): - def __init__(self, id=None, name=None, status=None, account_id=None, bridge_id=None, user_base_url=None, een_instance=None): + def __init__(self, id=None, name=None, status=dict(), account_id=None, bridge_id=None, user_base_url=None, een_instance=None): super().__init__(id=id, name=name, status=status, account_id=account_id, user_base_url=user_base_url, een_instance=een_instance) self.bridge_id = bridge_id self.previews = [] @@ -549,7 +713,7 @@ class Camera(Device): self.events = { 'status': [], 'motion': [] - } + } def get_list_of_events(self, start_timestamp=None, end_timestamp=None): @@ -576,7 +740,7 @@ class Camera(Device): } try: - response = requests.get(url, headers=headers, timeout=(3, 5)) + response = requests.get(url, headers=headers, timeout=self.een_instance._get_timeout_values('list_of_events')) response_json = response.json() logging.debug(f"{response.status_code} returned from {url} with {headers} and {response.text}") @@ -634,12 +798,13 @@ class Camera(Device): } try: - response = requests.get(url, headers=headers, timeout=(3, 5)) + response = requests.get(url, headers=headers, timeout=self.een_instance._get_timeout_values('live_preview')) logging.info(f"{response.status_code} in get_live_preview") except requests.exceptions.Timeout: logging.warn(f"timeout expired for {self.id} get_live_preview()") response = None + except requests.exceptions.RequestException as e: logging.warn(e) response = None