mirror of
https://github.com/PaiGramTeam/PaiGram.git
synced 2024-11-23 00:01:45 +00:00
185 lines
8.2 KiB
Python
185 lines
8.2 KiB
Python
|
from datetime import datetime, timedelta
|
||
|
from typing import List, Optional
|
||
|
|
||
|
from aiohttp import ClientConnectorError
|
||
|
from enkanetwork import (
|
||
|
EnkaNetworkAPI,
|
||
|
VaildateUIDError,
|
||
|
HTTPException,
|
||
|
EnkaPlayerNotFound,
|
||
|
PlayerInfo as EnkaPlayerInfo,
|
||
|
)
|
||
|
|
||
|
from core.base_service import BaseService
|
||
|
from core.basemodel import RegionEnum
|
||
|
from core.config import config
|
||
|
from core.dependence.redisdb import RedisDB
|
||
|
from core.services.players.models import PlayersDataBase as Player, PlayerInfoSQLModel, PlayerInfo
|
||
|
from core.services.players.repositories import PlayersRepository, PlayerInfoRepository
|
||
|
from utils.enkanetwork import RedisCache
|
||
|
from utils.log import logger
|
||
|
from utils.patch.aiohttp import AioHttpTimeoutException
|
||
|
|
||
|
__all__ = ("PlayersService", "PlayerInfoService")
|
||
|
|
||
|
|
||
|
class PlayersService(BaseService):
|
||
|
def __init__(self, players_repository: PlayersRepository) -> None:
|
||
|
self._repository = players_repository
|
||
|
|
||
|
async def get(
|
||
|
self,
|
||
|
user_id: int,
|
||
|
player_id: Optional[int] = None,
|
||
|
account_id: Optional[int] = None,
|
||
|
region: Optional[RegionEnum] = None,
|
||
|
is_chosen: Optional[bool] = None,
|
||
|
) -> Optional[Player]:
|
||
|
return await self._repository.get(user_id, player_id, account_id, region, is_chosen)
|
||
|
|
||
|
async def get_player(self, user_id: int, region: Optional[RegionEnum] = None) -> Optional[Player]:
|
||
|
return await self._repository.get(user_id, region=region, is_chosen=True)
|
||
|
|
||
|
async def add(self, player: Player) -> None:
|
||
|
await self._repository.add(player)
|
||
|
|
||
|
async def update(self, player: Player) -> None:
|
||
|
await self._repository.update(player)
|
||
|
|
||
|
async def get_all_by_user_id(self, user_id: int) -> List[Player]:
|
||
|
return await self._repository.get_all_by_user_id(user_id)
|
||
|
|
||
|
async def remove_all_by_user_id(self, user_id: int):
|
||
|
players = await self._repository.get_all_by_user_id(user_id)
|
||
|
for player in players:
|
||
|
await self._repository.delete(player)
|
||
|
|
||
|
async def delete(self, player: Player):
|
||
|
await self._repository.delete(player)
|
||
|
|
||
|
|
||
|
class PlayerInfoService(BaseService):
|
||
|
def __init__(self, redis: RedisDB, players_info_repository: PlayerInfoRepository):
|
||
|
self.cache = redis.client
|
||
|
self._players_info_repository = players_info_repository
|
||
|
self.enka_client = EnkaNetworkAPI(lang="chs", user_agent=config.enka_network_api_agent)
|
||
|
self.enka_client.set_cache(RedisCache(redis.client, key="players_info:enka_network", ttl=60))
|
||
|
self.qname = "players_info"
|
||
|
|
||
|
async def get_form_cache(self, player: Player):
|
||
|
qname = f"{self.qname}:{player.user_id}:{player.player_id}"
|
||
|
data = await self.cache.get(qname)
|
||
|
if data is None:
|
||
|
return None
|
||
|
json_data = str(data, encoding="utf-8")
|
||
|
return PlayerInfo.parse_raw(json_data)
|
||
|
|
||
|
async def set_form_cache(self, player: PlayerInfo):
|
||
|
qname = f"{self.qname}:{player.user_id}:{player.player_id}"
|
||
|
await self.cache.set(qname, player.json(), ex=60)
|
||
|
|
||
|
async def get_player_info_from_enka(self, player_id: int) -> Optional[EnkaPlayerInfo]:
|
||
|
try:
|
||
|
response = await self.enka_client.fetch_user(player_id, info=True)
|
||
|
return response.player
|
||
|
except (VaildateUIDError, EnkaPlayerNotFound, HTTPException) as exc:
|
||
|
logger.warning("EnkaNetwork 请求失败: %s", str(exc))
|
||
|
except AioHttpTimeoutException as exc:
|
||
|
logger.warning("EnkaNetwork 请求超时: %s", str(exc))
|
||
|
except ClientConnectorError as exc:
|
||
|
logger.warning("EnkaNetwork 请求错误: %s", str(exc))
|
||
|
except Exception as exc:
|
||
|
logger.error("EnkaNetwork 请求失败: %s", exc_info=exc)
|
||
|
return None
|
||
|
|
||
|
async def get(self, player: Player) -> Optional[PlayerInfo]:
|
||
|
player_info = await self.get_form_cache(player)
|
||
|
if player_info is not None:
|
||
|
return player_info
|
||
|
player_info = await self._players_info_repository.get(player.user_id, player.player_id)
|
||
|
if player_info is None:
|
||
|
player_info_enka = await self.get_player_info_from_enka(player.player_id)
|
||
|
if player_info_enka is None:
|
||
|
return None
|
||
|
player_info = PlayerInfo(
|
||
|
user_id=player.user_id,
|
||
|
player_id=player.player_id,
|
||
|
nickname=player_info_enka.nickname,
|
||
|
signature=player_info_enka.signature,
|
||
|
name_card=player_info_enka.namecard.id,
|
||
|
hand_image=player_info_enka.avatar.id,
|
||
|
create_time=datetime.now(),
|
||
|
last_save_time=datetime.now(),
|
||
|
is_update=True,
|
||
|
)
|
||
|
await self._players_info_repository.add(PlayerInfoSQLModel.from_orm(player_info))
|
||
|
await self.set_form_cache(player_info)
|
||
|
return player_info
|
||
|
if player_info.is_update:
|
||
|
expiration_time = datetime.now() - timedelta(days=7)
|
||
|
if player_info.last_save_time is None or player_info.last_save_time <= expiration_time:
|
||
|
player_info_enka = await self.get_player_info_from_enka(player.player_id)
|
||
|
if player_info_enka is None:
|
||
|
player_info.last_save_time = datetime.now()
|
||
|
await self._players_info_repository.update(PlayerInfoSQLModel.from_orm(player_info))
|
||
|
await self.set_form_cache(player_info)
|
||
|
return player_info
|
||
|
player_info.nickname = player_info_enka.nickname
|
||
|
player_info.name_card = player_info_enka.namecard.id
|
||
|
player_info.signature = player_info_enka.signature
|
||
|
player_info.hand_image = player_info_enka.avatar.id
|
||
|
player_info.nickname = player_info_enka.nickname
|
||
|
player_info.last_save_time = datetime.now()
|
||
|
await self._players_info_repository.update(PlayerInfoSQLModel.from_orm(player_info))
|
||
|
await self.set_form_cache(player_info)
|
||
|
return player_info
|
||
|
|
||
|
async def update_from_enka(self, player: Player) -> bool:
|
||
|
player_info = await self._players_info_repository.get(player.user_id, player.player_id)
|
||
|
if player_info is not None:
|
||
|
player_info_enka = await self.get_player_info_from_enka(player.player_id)
|
||
|
if player_info_enka is None:
|
||
|
return False
|
||
|
player_info.nickname = player_info_enka.nickname
|
||
|
player_info.name_card = player_info_enka.namecard.id
|
||
|
player_info.signature = player_info_enka.signature
|
||
|
player_info.hand_image = player_info_enka.avatar.id
|
||
|
player_info.nickname = player_info_enka.nickname
|
||
|
player_info.last_save_time = datetime.now()
|
||
|
await self._players_info_repository.update(player_info)
|
||
|
return True
|
||
|
return False
|
||
|
|
||
|
async def add_from_enka(self, player: Player) -> bool:
|
||
|
player_info = await self._players_info_repository.get(player.user_id, player.player_id)
|
||
|
if player_info is None:
|
||
|
player_info_enka = await self.get_player_info_from_enka(player.player_id)
|
||
|
if player_info_enka is None:
|
||
|
return False
|
||
|
player_info = PlayerInfoSQLModel(
|
||
|
user_id=player.user_id,
|
||
|
player_id=player.player_id,
|
||
|
nickname=player_info_enka.nickname,
|
||
|
signature=player_info_enka.signature,
|
||
|
name_card=player_info_enka.namecard.id,
|
||
|
hand_image=player_info_enka.avatar.id,
|
||
|
create_time=datetime.now(),
|
||
|
last_save_time=datetime.now(),
|
||
|
is_update=True,
|
||
|
)
|
||
|
await self._players_info_repository.add(player_info)
|
||
|
return True
|
||
|
return False
|
||
|
|
||
|
async def get_form_sql(self, player: Player):
|
||
|
return await self._players_info_repository.get(player.user_id, player.player_id)
|
||
|
|
||
|
async def delete_form_player(self, player: Player):
|
||
|
await self._players_info_repository.delete_by_id(user_id=player.user_id, player_id=player.player_id)
|
||
|
|
||
|
async def add(self, player_info: PlayerInfo):
|
||
|
await self._players_info_repository.add(PlayerInfoSQLModel.from_orm(player_info))
|
||
|
|
||
|
async def delete(self, player_info: PlayerInfo):
|
||
|
await self._players_info_repository.delete(PlayerInfoSQLModel.from_orm(player_info))
|