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'
Executable → Regular
+10 -2
View File
@@ -365,7 +365,12 @@ def update(record: dict, binary: Path, sha: str, start: bool, refresh_geoip: boo
if refresh_geoip:
# Shared lock with the runtime worker prevents concurrent upgrades.
geoip_lock_fd = acquire_geoip_update_lock(data, account.pw_uid, account.pw_gid)
geoip_stage, geoip_names = prepare_geoip_update(data, prefix)
try:
geoip_stage, geoip_names = prepare_geoip_update(data, prefix)
except GeoipUnavailable as error:
# GeoIP is refreshed best-effort: the update must not be blocked by a flaky download.
print(f'WARNING: GeoIP refresh skipped, keeping the installed country data: {error}', file=sys.stderr)
geoip_stage, geoip_names = None, []
active = subprocess.run(['systemctl', 'is-active', '--quiet', SERVICE], check=False, stdout=subprocess.DEVNULL).returncode == 0
stop_for_managed_update(data)
try:
@@ -434,7 +439,10 @@ def install(record: dict, binary: Path, sha: str, start: bool, install_geoip: bo
prefix.mkdir(parents=True, mode=0o755, exist_ok=True); os.chmod(prefix, 0o755)
data.mkdir(parents=True, mode=0o700, exist_ok=True); os.chmod(data, 0o700); os.chown(data, account.pw_uid, account.pw_gid)
if install_geoip:
download_geoip(data, account.pw_uid, account.pw_gid)
try:
download_geoip(data, account.pw_uid, account.pw_gid)
except GeoipUnavailable as error:
print(f'WARNING: GeoIP download skipped ({error}). Country allow/block lists will use data fetched later by the GeoIP updater, or rerun update.sh.', file=sys.stderr)
release, version = stage(binary, prefix, record['user'], sha)
record.update(release=release, version=version, sha256=sha)
switch(prefix, release)