Repository navigation
Expand file tree
/
Copy pathutils.py
More file actions
47 lines (41 loc) · 1.7 KB
/
Copy pathutils.py
File metadata and controls
47 lines (41 loc) · 1.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import time
import logging
import urllib.error
import urllib.request
from typing import Callable, Any, Tuple
logger = logging.getLogger(__name__)
def retry_network_operation(
max_retries: int = 3,
backoff_factor: float = 1.0,
exceptions: Tuple[type[Exception], ...] = (urllib.error.URLError, TimeoutError, ConnectionError)
):
"""
Decorator to retry network requests with exponential backoff for autoclicker syncing.
"""
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
def wrapper(*args: Any, **kwargs: Any) -> Any:
attempts = 0
while attempts < max_retries:
try:
return func(*args, **kwargs)
except exceptions as exc:
attempts += 1
if attempts >= max_retries:
logger.error("Network request failed after %d attempts: %s", max_retries, exc)
raise
delay = backoff_factor * (2 ** (attempts - 1))
logger.warning(
"Network error encountered: %s. Retrying in %.2fs (Attempt %d/%d)",
exc, delay, attempts, max_retries
)
time.sleep(delay)
return wrapper
return decorator
@retry_network_operation(max_retries=3, backoff_factor=0.5)
def fetch_remote_config(url: str, timeout: int = 5) -> str:
"""
Fetches remote autoclicker configuration or update metadata.
"""
req = urllib.request.Request(url, headers={"User-Agent": "AutoClicker/12.0"})
with urllib.request.urlopen(req, timeout=timeout) as response:
return response.read().decode("utf-8")