diff --git a/browserstack/local.py b/browserstack/local.py index 3dd5d1a..544c791 100644 --- a/browserstack/local.py +++ b/browserstack/local.py @@ -73,7 +73,12 @@ def start(self, **kwargs): self.binary_path = self.options['binarypath'] del self.options['binarypath'] else: - self.binary_path = LocalBinary().get_binary() + l = LocalBinary(self.key) + try: + self.binary_path = l.get_binary() + except Exception as e: + l = LocalBinary(self.key, e) + self.binary_path = l.get_binary() if 'logfile' in self.options: self.local_logfile_path = self.options['logfile'] diff --git a/browserstack/local_binary.py b/browserstack/local_binary.py index 72d1402..14ca29c 100644 --- a/browserstack/local_binary.py +++ b/browserstack/local_binary.py @@ -1,6 +1,7 @@ import platform, os, sys, stat, tempfile, re, subprocess from browserstack.bserrors import BrowserStackLocalError import gzip +import json try: from urllib.request import urlopen, Request @@ -10,11 +11,13 @@ class LocalBinary: _version = None - def __init__(self): + def __init__(self, key, error_object=None): + self.key = key + self.error_object = error_object is_64bits = sys.maxsize > 2**32 self.is_windows = False osname = platform.system() - source_url = "https://www.browserstack.com/local-testing/downloads/binaries/" + source_url = self.fetch_source_url() + '/' if osname == 'Darwin': self.http_path = source_url + "BrowserStackLocal-darwin-x64" @@ -37,6 +40,31 @@ def __init__(self): ] self.path_index = 0 + def fetch_source_url(self): + url = "https://local.browserstack.com/binary/api/v1/endpoint" + headers = { + "Content-Type": "application/json", + "Accept": "application/json" + } + data = {"auth_token": self.key} + + if self.error_object is not None: + data["error_message"] = str(self.error_object) + headers["X-Local-Fallback-Cloudflare"] = "true" + + req = Request(url, data=json.dumps(data).encode("utf-8")) + for key, value in headers.items(): + req.add_header(key, value) + + try: + with urlopen(req) as response: + resp_bytes = response.read() + resp_str = resp_bytes.decode('utf-8') + resp_json = json.loads(resp_str) + return resp_json["data"]["endpoint"] + except Exception as e: + raise BrowserStackLocalError('Error trying to fetch the source url for downloading the binary: {}'.format(e)) + @staticmethod def set_version(version): LocalBinary._version = version @@ -61,7 +89,7 @@ def __available_dir(self): return final_path else: self.path_index += 1 - raise BrowserStackLocalError('Error trying to download BrowserStack Local binary') + raise BrowserStackLocalError('Error trying to download BrowserStack Local binary, exhausted user directories to download to.') def download(self, chunk_size=8192, progress_hook=None): headers = { @@ -80,6 +108,7 @@ def download(self, chunk_size=8192, progress_hook=None): total_size = int(response.info().get_all('Content-Length')[0].strip() or '0') bytes_so_far = 0 + # Limits retries to the number of directories dest_parent_dir = self.__available_dir() dest_binary_name = 'BrowserStackLocal' if self.is_windows: