This commit is contained in:
Mateusz Gruszczyński committed 2026-11-08 09:55:44 +01:00
1 parent 6ef01212ec
commit d7fb869783
4 files changed
+41 -6

No files matched your search

Executable → Regular
+27 -1
View File
@@ -28,6 +28,7 @@ import subprocess
import sys
import time
import uuid
import urllib.error
import urllib.request
import urllib.parse
@@ -41,6 +42,12 @@ GEOIP_SOURCES = {
'user-country-ipv6.csv': 'https://github.com/sapics/ip-location-db/releases/download/latest/user-country-ipv6.csv',
}
GEOIP_MAX_BYTES = 256 * 1024 * 1024
GEOIP_FETCH_ATTEMPTS = 4
GEOIP_RETRY_DELAYS = (3, 6, 12)
class GeoipUnavailable(RuntimeError):
"""The GeoIP CSV download failed after retries; the deployment itself can continue."""
def run(args: list[str], **kwargs) -> subprocess.CompletedProcess:
@@ -93,7 +100,7 @@ def digest(path: Path) -> str:
return result.hexdigest()
def fetch_https(url: str, max_bytes: int) -> bytes:
def _fetch_https_once(url: str, max_bytes: int) -> bytes:
if urllib.parse.urlparse(url).scheme != 'https':
raise ValueError('GeoIP downloads require HTTPS.')
request = urllib.request.Request(url, headers={'User-Agent': 'RustProxy-installer'})
@@ -114,6 +121,25 @@ def fetch_https(url: str, max_bytes: int) -> bytes:
return bytes(result)
def fetch_https(url: str, max_bytes: int) -> bytes:
"""Download with retries; transient gateway/network failures (502/503/504, timeouts) are retried."""
last: BaseException | None = None
for attempt in range(GEOIP_FETCH_ATTEMPTS):
try:
return _fetch_https_once(url, max_bytes)
except urllib.error.HTTPError as error:
last = error
if error.code not in (408, 425, 429) and error.code < 500:
break
except (urllib.error.URLError, TimeoutError, ConnectionError, ssl.SSLError) as error:
last = error
if attempt + 1 < GEOIP_FETCH_ATTEMPTS:
delay = GEOIP_RETRY_DELAYS[min(attempt, len(GEOIP_RETRY_DELAYS) - 1)]
print(f'GeoIP download failed ({last}); retrying in {delay}s ({attempt + 1}/{GEOIP_FETCH_ATTEMPTS - 1}).', file=sys.stderr)
time.sleep(delay)
raise GeoipUnavailable(f'GeoIP download from {url} failed: {last}')
def acquire_geoip_update_lock(data: Path, uid: int | None = None, gid: int | None = None) -> int:
"""Serialize installer/manual GeoIP refresh with the in-process worker."""
path = data / '.geoip-update.lock'