diff --git a/wideq/core.py b/wideq/core.py index e74ed9f..f8293d3 100644 --- a/wideq/core.py +++ b/wideq/core.py @@ -9,6 +9,8 @@ import datetime import requests import logging from typing import Any, Dict, List, Tuple +from requests.adapters import HTTPAdapter +from requests.packages.urllib3.util.retry import Retry GATEWAY_URL = 'https://kic.lgthinq.com:46030/api/common/gatewayUriList' APP_KEY = 'wideq' @@ -21,6 +23,9 @@ OAUTH_CLIENT_KEY = 'LGAO221A02' DATE_FORMAT = '%a, %d %b %Y %H:%M:%S +0000' DEFAULT_COUNTRY = 'US' DEFAULT_LANGUAGE = 'en-US' +NUM_RETRIES = 5 # Anecdotally this seems sufficient. +BACKOFF_FACTOR = 0.5 +STATUS_FORCELIST = (502, 503, 504) def get_wideq_logger() -> logging.Logger: @@ -59,6 +64,26 @@ def get_wideq_logger() -> logging.Logger: LOGGER = get_wideq_logger() +def get_retry_session(): + # See https://www.peterbe.com/plog/best-practice-with-retries-with-requests + # for the source of this retry mechanism + session = requests.Session() + retry = Retry( + total=NUM_RETRIES, + read=NUM_RETRIES, + connect=NUM_RETRIES, + backoff_factor=BACKOFF_FACTOR, + status_forcelist=STATUS_FORCELIST, + ) + adapter = HTTPAdapter(max_retries=retry) + session.mount('http://', adapter) + session.mount('https://', adapter) + return session + + +SESSION = get_retry_session() + + def set_log_level(level: int): logger = get_wideq_logger() logger.setLevel(level) @@ -163,7 +188,6 @@ def lgedm_post(url, data=None, access_token=None, session_id=None): authenticated requests. They are not required, for example, to load the gateway server data or to start a session. """ - headers = { 'x-thinq-application-key': APP_KEY, 'x-thinq-security-key': SECURITY_KEY, @@ -174,7 +198,7 @@ def lgedm_post(url, data=None, access_token=None, session_id=None): if session_id: headers['x-thinq-jsessionId'] = session_id - res = requests.post(url, json={DATA_ROOT: data}, headers=headers) + res = SESSION.post(url, json={DATA_ROOT: data}, headers=headers) out = res.json()[DATA_ROOT] # Check for API errors. @@ -266,7 +290,7 @@ def refresh_auth(oauth_root, refresh_token): 'Accept': 'application/json', } - res = requests.post(token_url, data=data, headers=headers) + res = SESSION.post(token_url, data=data, headers=headers) res_data = res.json() if res_data['status'] != 1: