️ 为 IO 添加缓存

This commit is contained in:
2023-11-22 13:22:18 +08:00
parent c75c6b73bd
commit b773fb44a1
3 changed files with 49 additions and 36 deletions

View File

@@ -0,0 +1,28 @@
from datetime import UTC, datetime
from aiocache import Cache as ACache # type: ignore[import-untyped]
from nonebot.log import logger
from pydantic import parse_raw_as
from ...utils.request import Request
from .schemas.base import FailedModel, SuccessModel
class Cache:
cache = ACache(ACache.MEMORY)
@classmethod
async def get(cls, url: str) -> bytes:
cached_data = await cls.cache.get(url)
if cached_data is None:
response_data = await Request.request(url)
parsed_data: SuccessModel | FailedModel = parse_raw_as(SuccessModel | FailedModel, response_data) # type: ignore[arg-type]
if isinstance(parsed_data, SuccessModel):
await cls.cache.add(
url,
response_data,
(parsed_data.cache.cached_until - datetime.now(UTC)).total_seconds(),
)
return response_data
logger.debug(f'{url}: Cache hit!')
return cached_data

View File

@@ -13,22 +13,19 @@ from sqlalchemy import select
from ...db import create_or_update_bind from ...db import create_or_update_bind
from ...utils.exception import MessageFormatError, RequestError, WhatTheFuckError from ...utils.exception import MessageFormatError, RequestError, WhatTheFuckError
from ...utils.request import Request, splice_url from ...utils.request import splice_url
from ...utils.typing import GameType from ...utils.typing import GameType
from .. import Processor as ProcessorMeta from .. import Processor as ProcessorMeta
from ..schemas import BaseUser from .cache import Cache
from .constant import BASE_URL, GAME_TYPE, RANK_PERCENTILE from .constant import BASE_URL, GAME_TYPE, RANK_PERCENTILE
from .model import IORank from .model import IORank
from .schemas.league_all import FailedModel as LeagueAllFailed from .schemas.league_all import FailedModel as LeagueAllFailed
from .schemas.league_all import LeagueAll from .schemas.league_all import LeagueAll
from .schemas.league_all import ValidUser as LeagueAllUser from .schemas.league_all import ValidUser as LeagueAllUser
from .schemas.response import ProcessedData, RawResponse from .schemas.response import ProcessedData, RawResponse
from .schemas.user import User
from .schemas.user_info import FailedModel as InfoFailed from .schemas.user_info import FailedModel as InfoFailed
from .schemas.user_info import ( from .schemas.user_info import NeverPlayedLeague, NeverRatedLeague, UserInfo
NeverPlayedLeague,
NeverRatedLeague,
UserInfo,
)
from .schemas.user_info import SuccessModel as InfoSuccess from .schemas.user_info import SuccessModel as InfoSuccess
from .schemas.user_records import FailedModel as RecordsFailed from .schemas.user_records import FailedModel as RecordsFailed
from .schemas.user_records import SoloRecord, UserRecords from .schemas.user_records import SoloRecord, UserRecords
@@ -38,17 +35,6 @@ from .typing import Rank
driver = get_driver() driver = get_driver()
class User(BaseUser):
ID: str | None = None
name: str | None = None
@property
def unique_identifier(self) -> str:
if self.ID is None:
raise ValueError('不完整的User!')
return self.ID
def identify_user_info(info: str) -> User | MessageFormatError: def identify_user_info(info: str) -> User | MessageFormatError:
if match(r'^[a-f0-9]{24}$', info): if match(r'^[a-f0-9]{24}$', info):
return User(ID=info) return User(ID=info)
@@ -104,7 +90,7 @@ class Processor(ProcessorMeta):
async def get_user_info(self) -> InfoSuccess: async def get_user_info(self) -> InfoSuccess:
"""获取用户数据""" """获取用户数据"""
if self.processed_data.user_info is None: if self.processed_data.user_info is None:
self.raw_response.user_info = await Request.request( self.raw_response.user_info = await Cache.get(
splice_url([BASE_URL, 'users/', f'{self.user.ID or self.user.name}']) splice_url([BASE_URL, 'users/', f'{self.user.ID or self.user.name}'])
) )
user_info: UserInfo = parse_raw_as(UserInfo, self.raw_response.user_info) # type: ignore[arg-type] user_info: UserInfo = parse_raw_as(UserInfo, self.raw_response.user_info) # type: ignore[arg-type]
@@ -116,20 +102,10 @@ class Processor(ProcessorMeta):
async def get_user_records(self) -> RecordsSuccess: async def get_user_records(self) -> RecordsSuccess:
"""获取Solo数据""" """获取Solo数据"""
if self.processed_data.user_records is None: if self.processed_data.user_records is None:
self.raw_response.user_records = await Request.request( self.raw_response.user_records = await Cache.get(
splice_url( splice_url([BASE_URL, 'users/', f'{self.user.ID or self.user.name}/', 'records'])
[
BASE_URL,
'users/',
f'{self.user.ID or self.user.name}/',
'records',
]
)
)
user_records: UserRecords = parse_raw_as(
UserRecords, # type: ignore[arg-type]
self.raw_response.user_records,
) )
user_records: UserRecords = parse_raw_as(UserRecords, self.raw_response.user_records) # type: ignore[arg-type]
if isinstance(user_records, RecordsFailed): if isinstance(user_records, RecordsFailed):
raise RequestError(f'用户Solo数据请求错误:\n{user_records.error}') raise RequestError(f'用户Solo数据请求错误:\n{user_records.error}')
self.processed_data.user_records = user_records self.processed_data.user_records = user_records
@@ -178,10 +154,7 @@ class Processor(ProcessorMeta):
@scheduler.scheduled_job('cron', hour='0,6,12,18', minute=0) @scheduler.scheduled_job('cron', hour='0,6,12,18', minute=0)
async def get_io_rank_data() -> None: async def get_io_rank_data() -> None:
league_all: LeagueAll = parse_raw_as( league_all: LeagueAll = parse_raw_as(LeagueAll, await Cache.get(splice_url([BASE_URL, 'users/lists/league/all']))) # type: ignore[arg-type]
LeagueAll, # type: ignore[arg-type]
await Request.request(splice_url([BASE_URL, 'users/lists/league/all'])),
)
if isinstance(league_all, LeagueAllFailed): if isinstance(league_all, LeagueAllFailed):
raise RequestError(f'用户Solo数据请求错误:\n{league_all.error}') raise RequestError(f'用户Solo数据请求错误:\n{league_all.error}')

View File

@@ -0,0 +1,12 @@
from ...schemas import BaseUser
class User(BaseUser):
ID: str | None = None
name: str | None = None
@property
def unique_identifier(self) -> str:
if self.ID is None:
raise ValueError('不完整的User!')
return self.ID