This commit is contained in:
2026-11-04 15:35:15 +08:00
parent 4709ea4328
commit 62291c57ec
12 changed files with 363 additions and 72 deletions
+13 -10
View File
@@ -1,7 +1,6 @@
"""官方寄售缓存、认证失败识别及可选BARK通知。"""
import asyncio
from datetime import datetime, timezone
import hashlib
import json
import logging
@@ -14,6 +13,7 @@ import aiohttp
from api.core.Gzip import gzip_unzip, gzip_zip
from api.types.colg import GOLD_REGION_CODES, OfficialGold
from api.utils.thirdpart_gold import RELEASE_LOCK
from api.utils.gold_time import UPDATE_LEAD_SECONDS, half_hour_start, refresh_slot
from config.main import config
logger = logging.getLogger('dcalc.official_gold')
@@ -43,14 +43,14 @@ def normalize_row(item: dict) -> dict:
except (TypeError, ValueError, OverflowError):
continue
if math.isfinite(price):
prices.append(price)
prices.append(round(price, 2))
ranks[name] = prices
ratios = [10000 / price for prices in ranks.values() for price in prices
if price > 0 and math.isfinite(10000 / price)]
return OfficialGold.model_validate({
**item, **ranks,
'max': round(max(ratios), 4) if ratios else None,
'min': round(min(ratios), 4) if ratios else None,
**item, **ranks, 'updataTime': str(half_hour_start(int(item['updataTime']))),
'max': round(max(ratios), 2) if ratios else None,
'min': round(min(ratios), 2) if ratios else None,
}).model_dump()
@@ -64,7 +64,10 @@ def is_auth_failure(payload: dict) -> bool:
))
async def fetch_gold() -> list[dict]:
async def fetch_gold(*, started_at: float | None = None) -> list[dict]:
if started_at is None:
started_at = time.time()
update_time = str(refresh_slot(started_at))
timeout = aiohttp.ClientTimeout(total=10)
async with aiohttp.ClientSession(timeout=timeout) as session:
async def fetch_region(region):
@@ -81,7 +84,7 @@ async def fetch_gold() -> list[dict]:
resp.raise_for_status()
data = payload['data']
return normalize_row({
'updataTime': str(int(datetime.now(timezone.utc).timestamp())),
'updataTime': update_time,
'region': f'跨{region}', 'code': GOLD_REGION_CODES[f'跨{region}'],
'goldDealRank': [float(item['price']) for item in data['godDealRank'][:5]],
'goldTopDealRank': [float(item['price']) for item in data['godTopDealRank'][:5]],
@@ -150,7 +153,7 @@ async def read_cache(redis) -> list[dict]:
for item in json.loads(gzip_unzip(value))]
if [row['region'] for row in rows] != [f'跨{region}' for region in REGIONS]:
return []
if any(not 0 <= time.time() - int(row['updataTime']) < RETENTION_SECONDS for row in rows):
if any(not -UPDATE_LEAD_SECONDS <= time.time() - int(row['updataTime']) < RETENTION_SECONDS for row in rows):
return []
return rows
except (ValueError, TypeError, KeyError, OSError):
@@ -160,7 +163,7 @@ async def read_cache(redis) -> list[dict]:
def is_fresh(rows: list[dict]) -> bool:
return (len(rows) == len(REGIONS)
and all(0 <= time.time() - int(row['updataTime']) < FRESH_SECONDS for row in rows))
and all(int(row['updataTime']) == refresh_slot() for row in rows))
async def refresh_cache(redis) -> bool:
@@ -173,7 +176,7 @@ async def refresh_cache(redis) -> bool:
if is_fresh(await read_cache(redis)) or await redis.get(COOLDOWN_KEY):
return False
try:
data = await fetch_gold()
data = await fetch_gold(started_at=time.time())
except TokenExpired:
logger.warning('official gold authentication failed; check HELPER_TOKEN and HELPER_ID')
await notify_token_expired(redis)