|  |  | @ -6,6 +6,7 @@ from hashlib import sha256 | 
			
		
	
		
		
			
				
					
					|  |  |  | from urllib3 import PoolManager |  |  |  | from urllib3 import PoolManager | 
			
		
	
		
		
			
				
					
					|  |  |  | from urllib3.util import Timeout |  |  |  | from urllib3.util import Timeout | 
			
		
	
		
		
			
				
					
					|  |  |  | from tenacity import retry, wait_random_exponential, stop_after_attempt |  |  |  | from tenacity import retry, wait_random_exponential, stop_after_attempt | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | from typing import Optional | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | from openpilot.common.file_helpers import atomic_write_in_dir |  |  |  | from openpilot.common.file_helpers import atomic_write_in_dir | 
			
		
	
		
		
			
				
					
					|  |  |  | from openpilot.system.hardware.hw import Paths |  |  |  | from openpilot.system.hardware.hw import Paths | 
			
		
	
	
		
		
			
				
					|  |  | @ -25,9 +26,12 @@ class URLFileException(Exception): | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | class URLFile: |  |  |  | class URLFile: | 
			
		
	
		
		
			
				
					
					|  |  |  |   _tlocal = threading.local() |  |  |  |   _pid: Optional[int] = None | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   _pool_manager: Optional[PoolManager] = None | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   _pool_manager_lock = threading.Lock() | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   def __init__(self, url, debug=False, cache=None): |  |  |  |   def __init__(self, url, debug=False, cache=None): | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     self._pool_manager = None | 
			
		
	
		
		
			
				
					
					|  |  |  |     self._url = url |  |  |  |     self._url = url | 
			
		
	
		
		
			
				
					
					|  |  |  |     self._pos = 0 |  |  |  |     self._pos = 0 | 
			
		
	
		
		
			
				
					
					|  |  |  |     self._length = None |  |  |  |     self._length = None | 
			
		
	
	
		
		
			
				
					|  |  | @ -41,11 +45,6 @@ class URLFile: | 
			
		
	
		
		
			
				
					
					|  |  |  |     if not self._force_download: |  |  |  |     if not self._force_download: | 
			
		
	
		
		
			
				
					
					|  |  |  |       os.makedirs(Paths.download_cache_root(), exist_ok=True) |  |  |  |       os.makedirs(Paths.download_cache_root(), exist_ok=True) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     try: |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       self._http_client = URLFile._tlocal.http_client |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     except AttributeError: |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       self._http_client = URLFile._tlocal.http_client = PoolManager() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   def __enter__(self): |  |  |  |   def __enter__(self): | 
			
		
	
		
		
			
				
					
					|  |  |  |     return self |  |  |  |     return self | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -55,10 +54,20 @@ class URLFile: | 
			
		
	
		
		
			
				
					
					|  |  |  |       self._local_file.close() |  |  |  |       self._local_file.close() | 
			
		
	
		
		
			
				
					
					|  |  |  |       self._local_file = None |  |  |  |       self._local_file = None | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   def _http_client(self) -> PoolManager: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     if self._pool_manager is None: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       pid = os.getpid() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       with URLFile._pool_manager_lock: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if URLFile._pid != pid or URLFile._pool_manager is None: # unsafe to share after fork | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           URLFile._pid = pid | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           URLFile._pool_manager = PoolManager(num_pools=10, maxsize=10) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       self._pool_manager = URLFile._pool_manager | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     return self._pool_manager | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   @retry(wait=wait_random_exponential(multiplier=1, max=5), stop=stop_after_attempt(3), reraise=True) |  |  |  |   @retry(wait=wait_random_exponential(multiplier=1, max=5), stop=stop_after_attempt(3), reraise=True) | 
			
		
	
		
		
			
				
					
					|  |  |  |   def get_length_online(self): |  |  |  |   def get_length_online(self): | 
			
		
	
		
		
			
				
					
					|  |  |  |     timeout = Timeout(connect=50.0, read=500.0) |  |  |  |     timeout = Timeout(connect=50.0, read=500.0) | 
			
		
	
		
		
			
				
					
					|  |  |  |     response = self._http_client.request('HEAD', self._url, timeout=timeout, preload_content=False) |  |  |  |     response = self._http_client().request('HEAD', self._url, timeout=timeout, preload_content=False) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     if not (200 <= response.status <= 299): |  |  |  |     if not (200 <= response.status <= 299): | 
			
		
	
		
		
			
				
					
					|  |  |  |       return -1 |  |  |  |       return -1 | 
			
		
	
		
		
			
				
					
					|  |  |  |     length = response.headers.get('content-length', 0) |  |  |  |     length = response.headers.get('content-length', 0) | 
			
		
	
	
		
		
			
				
					|  |  | @ -131,7 +140,7 @@ class URLFile: | 
			
		
	
		
		
			
				
					
					|  |  |  |       t1 = time.time() |  |  |  |       t1 = time.time() | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     timeout = Timeout(connect=50.0, read=500.0) |  |  |  |     timeout = Timeout(connect=50.0, read=500.0) | 
			
		
	
		
		
			
				
					
					|  |  |  |     response = self._http_client.request('GET', self._url, timeout=timeout, preload_content=False, headers=headers) |  |  |  |     response = self._http_client().request('GET', self._url, timeout=timeout, preload_content=False, headers=headers) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     ret = response.data |  |  |  |     ret = response.data | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     if self._debug: |  |  |  |     if self._debug: | 
			
		
	
	
		
		
			
				
					|  |  | 
 |