File size: 2,257 Bytes
97873ec
476cee0
97873ec
476cee0
 
97873ec
476cee0
97873ec
 
 
 
476cee0
 
 
 
 
 
 
 
 
97873ec
 
 
476cee0
 
 
 
97873ec
476cee0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
"""
Background price cache with multi-API fallback and rate-limit handling
"""
import httpx
import logging

# Primary and secondary APIs for crypto prices
COINGECKO_URL = (
    "https://api.coingecko.com/api/v3/simple/price"
    "?ids=bitcoin,ethereum,dogecoin&vs_currencies=usd"
)
COINCAP_URL = (
    "https://api.coincap.io/v2/assets?ids=bitcoin,ethereum,dogecoin"
)

# Shared price cache
CURRENT_PRICES = {"bitcoin": "--", "ethereum": "--", "dogecoin": "--"}

# How often to retry each API before falling back (seconds)
RETRY_DELAY = 5


def fetch_prices() -> None:
    """
    Try CoinGecko first; on 429 or error, fall back to CoinCap.
    Updates CURRENT_PRICES in-place.
    """
    global CURRENT_PRICES
    apis = [
        ("CoinGecko", COINGECKO_URL),
        ("CoinCap", COINCAP_URL)
    ]

    for name, url in apis:
        try:
            resp = httpx.get(url, timeout=10)
            # Handle CoinCap JSON structure separately
            if name == "CoinGecko":
                resp.raise_for_status()
                data = resp.json()
                prices = {
                    "bitcoin": data["bitcoin"]["usd"],
                    "ethereum": data["ethereum"]["usd"],
                    "dogecoin": data["dogecoin"]["usd"]
                }
            else:
                resp.raise_for_status()
                data = resp.json().get("data", [])
                prices = {item["id"]: float(item["priceUsd"]) for item in data}

            CURRENT_PRICES.update(prices)
            logging.info("✅ [%s] prices updated: %s", name, prices)
            return

        except httpx.HTTPStatusError as e:
            status = e.response.status_code
            if status == 429:
                logging.warning("⚠️ [%s] rate limit (429). Retrying fallback.", name)
            else:
                logging.warning("⚠️ [%s] HTTP error %s: %s", name, status, e)
        except Exception as e:
            logging.warning("⚠️ [%s] fetch error: %s", name, e)

        # If we reach here, wait a bit before trying next API
        try:
            import time; time.sleep(RETRY_DELAY)
        except Exception:
            pass

    logging.error("❌ All price APIs failed. Keeping previous prices: %s", CURRENT_PRICES)