This commit is contained in:
2026-08-18 16:13:07 +08:00
parent efcbc49096
commit 4de893ca94
12 changed files with 906 additions and 506 deletions
+32 -33
View File
@@ -1,4 +1,5 @@
import asyncio
import logging
from api.types.colg import HistoryGold, OfficialGold, RealTimeGold
from api.core.Gzip import register_gzip_request
@@ -6,7 +7,7 @@ import json
from fastapi import APIRouter, Query
from api.core.Response import response
from api.core.Redis import get_redis_info, get_redis_info_async
from api.dp import RedisDep
from api.dp import AsyncRedisDep, RedisDep
from typing import Annotated
import requests
from config.main import config
@@ -15,6 +16,7 @@ from api.core.Response import Return as Response
import aiohttp
router = APIRouter()
logger = logging.getLogger('dcalc.colg')
register_gzip_request(router)
@@ -39,6 +41,29 @@ payload_helper = {
'token': config.HELPER_TOKEN,
}
OFFICIAL_GOLD_URL = 'https://dzhu.qq.com/zangyi/activity/app'
OFFICIAL_GOLD_REGIONS = ('1', '2', '3A', '3B', '4', '5', '6', '7')
async def _fetch_official_gold() -> list[dict]:
timeout = aiohttp.ClientTimeout(total=10)
async with aiohttp.ClientSession(timeout=timeout) as session:
async def fetch_region(region: str) -> dict:
form = {**payload_helper, 'serverNo': region}
async with session.post(OFFICIAL_GOLD_URL, data=form) as resp:
resp.raise_for_status()
payload = await resp.json(content_type=None)
data = payload['data']
return {
'updataTime': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
'region': f'跨{region}',
'goldDealRank': [int(item['price']) for item in data['godDealRank']],
'goldTopDealRank': [int(item['price']) for item in data['godTopDealRank']],
}
return await asyncio.gather(*(fetch_region(region) for region in OFFICIAL_GOLD_REGIONS))
def get_date_str(timestamp: int) -> str:
utc_time = datetime.fromtimestamp(timestamp, tz=timezone.utc)
@@ -47,7 +72,7 @@ def get_date_str(timestamp: int) -> str:
@router.get('/gold/realtime/', operation_id='realtimeGold', response_model=Response[list[RealTimeGold]])
async def get_real_time_gold(redis: RedisDep) -> Response[list[RealTimeGold]]:
def get_real_time_gold(redis: RedisDep) -> Response[list[RealTimeGold]]:
"""
返回所有跨区的实时金价信息
"""
@@ -74,7 +99,7 @@ async def get_real_time_gold(redis: RedisDep) -> Response[list[RealTimeGold]]:
@router.get('/gold/history/', operation_id='historyGold', response_model=Response[HistoryGold] | Response[None])
async def get_history_gold(region: Annotated[int, Query(..., description='跨区id')], timeRange: Annotated[int, Query(..., description='时间跨度天数')] = 7) -> Response[HistoryGold] | Response[None]:
def get_history_gold(region: Annotated[int, Query(..., description='跨区id')], timeRange: Annotated[int, Query(..., description='时间跨度天数')] = 7) -> Response[HistoryGold] | Response[None]:
"""
获取历史金价数据
@@ -146,7 +171,7 @@ async def get_history_gold(region: Annotated[int, Query(..., description='跨区
@router.get('/gold/official/', operation_id='officialGold', response_model=Response[list[OfficialGold]])
async def get_official_gold(redis: RedisDep) -> Response[list[OfficialGold]]:
async def get_official_gold(redis: AsyncRedisDep) -> Response[list[OfficialGold]]:
"""
获取DNF官方金币寄售实时数据
@@ -156,36 +181,10 @@ async def get_official_gold(redis: RedisDep) -> Response[list[OfficialGold]]:
- 该接口会返回所有跨区的官方金币寄售数据,包括最低成交价排名前5的价格和最高成交价排名前5的价格
- 数据来源于DNF官方提供的接口,可能会有一定的延迟和不稳定性
"""
official_url = 'https://dzhu.qq.com/zangyi/activity/app'
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
key = 'openapi:colg:real_time_gold_officical'
list = ['1', '2', '3A', '3B', '4', '5', '6', '7']
try:
async def get_data():
datas = []
async with aiohttp.ClientSession() as session:
tasks = []
for i in list:
payload_helper['serverNo'] = i
query = '&'.join(f'{k}={v}' for k, v in payload_helper.items())
tasks.append(session.post(official_url, data=query, headers=headers, timeout=10))
responses = await asyncio.gather(*tasks)
for index, resp in enumerate(responses):
res = json.loads(await resp.read())
datas.append(
{
'updataTime': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
'region': f'跨{list[index]}',
'goldDealRank': [int(i.get('price')) for i in res['data']['godDealRank']],
'goldTopDealRank': [int(i.get('price')) for i in res['data']['godTopDealRank']],
}
)
return datas
except Exception as e:
print(e)
data = await get_redis_info_async(redis, key, _fetch_official_gold, 30 * 60)
except Exception:
logger.exception('fetch official gold failed')
return response(data=[])
# 设置半小时过期一次
data = await get_redis_info_async(redis, key, get_data, 30 * 60)
return response(data=data)
+10 -10
View File
@@ -4,7 +4,7 @@ from fastapi import APIRouter, Body, Request, Response
from api.core.Auth import createToken
from api.core.Response import response
from api.core.Redis import get_redis_info, get_redis_info_async
from api.dp import RedisDep, AltersDep
from api.dp import AsyncRedisDep, RedisDep, AltersDep
from core.basic.equipment import get_equipment
from core.character.adventure import get_adv_info, get_adv_list
from core.basic.character import createCharacter
@@ -21,7 +21,7 @@ register_gzip_request(router)
@router.get('/adventure')
async def get_adventure_info(request: Request, redis: RedisDep, name: str = None):
def get_adventure_info(request: Request, redis: RedisDep, name: str = None):
adventure_info = get_redis_info(redis, 'dcalc:adventure', get_adv_list)
if name:
total = [item for job in adventure_info for item in job.get('children', [])]
@@ -31,7 +31,7 @@ async def get_adventure_info(request: Request, redis: RedisDep, name: str = None
@router.get('/token/get/{alter}')
async def getToken(redis: RedisDep, alter: str, request: Request, version: str = None, equVersion: str = '0'):
def getToken(redis: RedisDep, alter: str, request: Request, version: str = None, equVersion: str = '0'):
if get_adv_info(alter) is None:
raise ResponseException('无效的职业')
token = createToken(alter, equVersion, redis)
@@ -39,7 +39,7 @@ async def getToken(redis: RedisDep, alter: str, request: Request, version: str =
@router.get('/character')
async def get_character_info(request: Request, state: AltersDep, redis: RedisDep):
def get_character_info(request: Request, state: AltersDep, redis: RedisDep):
def get_character():
return createCharacter(state.alter, state.equVersion).getInfo()
@@ -56,7 +56,7 @@ async def get_character_info(request: Request, state: AltersDep, redis: RedisDep
@router.get('/info/oath/{suitId}/{skillId}')
async def get_oath_info(state: AltersDep, suitId: str, skillId: str, rarity: str, lv: int, redis: RedisDep):
def get_oath_info(state: AltersDep, suitId: str, skillId: str, rarity: str, lv: int, redis: RedisDep):
def get_info():
skill = None
version = state.equVersion
@@ -73,7 +73,7 @@ async def get_oath_info(state: AltersDep, suitId: str, skillId: str, rarity: str
@router.get('/skill/{skillId}/{level}')
async def get_skill_info(state: AltersDep, skillId: str, level: int, redis: RedisDep):
def get_skill_info(state: AltersDep, skillId: str, level: int, redis: RedisDep):
"""
获取技能信息
"""
@@ -99,7 +99,7 @@ async def get_skill_info(state: AltersDep, skillId: str, level: int, redis: Redi
@router.get('/dnfhelper/{uid}/list')
async def get_dnfhelper_list(uid: str, redis: RedisDep):
async def get_dnfhelper_list(uid: str, redis: AsyncRedisDep):
cache_key = f'dnfhelper:{uid}'
async def get_list():
@@ -111,7 +111,7 @@ async def get_dnfhelper_list(uid: str, redis: RedisDep):
@router.get('/dnfhelper/{uid}/{id}/')
async def get_dnfhelper_detail(uid: str, id: str, state: AltersDep, redis: RedisDep):
async def get_dnfhelper_detail(uid: str, id: str, state: AltersDep, redis: AsyncRedisDep):
cache_key = f'dnfhelper:{uid}:{id}'
async def get_detail():
@@ -123,7 +123,7 @@ async def get_dnfhelper_detail(uid: str, id: str, state: AltersDep, redis: Redis
@router.get('/dnfhelper/{uid}/')
async def get_info_by_dnfhelper(uid: str, state: AltersDep, redis: RedisDep):
async def get_info_by_dnfhelper(uid: str, state: AltersDep):
try:
result = await get_user_info_by_id(uid, state)
return response(data=result)
@@ -134,7 +134,7 @@ async def get_info_by_dnfhelper(uid: str, state: AltersDep, redis: RedisDep):
@router.post('/skillTree/')
async def get_skill_by_code(state: AltersDep, code=Body(None)):
def get_skill_by_code(state: AltersDep, code=Body(None)):
try:
skills = get_skill_tree_info(code.get('code', ''))
if skills.get('job', {}).get('class', '') != state.alter.replace('_carry', ''):
+5 -5
View File
@@ -31,7 +31,7 @@ register_gzip_request(router)
@router.get('/skills/', operation_id='skillsList', response_model=SearchSkillResponse)
async def get_skills_list(
def get_skills_list(
redis: RedisDep,
skillName: Annotated[str | None, Query(description='技能名称,支持模糊查询')] = None,
) -> SearchSkillResponse:
@@ -62,7 +62,7 @@ async def get_skills_list(
@router.get('/jobInfo/', operation_id='jobsInfo', response_model=JobInfoResponse)
async def get_jobs_info(
def get_jobs_info(
redis: RedisDep,
jobName: Annotated[str, Query(..., description='职业名称,支持模糊查询')] = None,
) -> JobInfoResponse:
@@ -98,7 +98,7 @@ async def get_jobs_info(
@router.get('/{jobId}/{jobGrowId}/skills/', operation_id='skillsByJob', response_model=SkillsListResponse)
async def get_cn_skills_by_job(
def get_cn_skills_by_job(
redis: RedisDep,
jobId: Annotated[str, Path(..., description='职业')],
jobGrowId: Annotated[str, Path(..., description='转职')],
@@ -122,7 +122,7 @@ async def get_cn_skills_by_job(
@router.get('/{jobId}/{jobGrowId}/{skillId}/', operation_id='skillDetail', response_model=SkillDetailResponse)
async def get_cn_skill_info(
def get_cn_skill_info(
redis: RedisDep,
jobId: Annotated[str, Path(..., description='职业')],
jobGrowId: Annotated[str, Path(..., description='转职')],
@@ -164,7 +164,7 @@ async def get_cn_skill_info(
@router.get('/skillData/summary/', operation_id='skillDataSummary', response_model=SkillDataSummaryResponse)
async def get_skill_data_summary(
def get_skill_data_summary(
redis: RedisDep,
job: Annotated[str, Query(description='职业')],
skills: Annotated[