Add NeedChallenge and NotSupported exception

This commit is contained in:
luoshuijs 2023-06-11 15:15:00 +08:00 committed by GitHub
parent 888c729e1f
commit e6ec72272b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 100 additions and 21 deletions

View File

@ -8,6 +8,7 @@ from simnet.client.routes import (
GET_COOKIES_TOKEN_BY_STOKEN_URL,
GET_LTOKEN_BY_STOKEN_URL,
)
from simnet.errors import RegionNotSupported
from simnet.utils.enum_ import Region
__all__ = ("AuthClient",)
@ -36,11 +37,11 @@ class AuthClient(BaseClient):
Optional[str]: The retrieved super ticket (`stoken`).
Raises:
RuntimeError: This method is only available for the Chinese region.
RegionNotSupported: This method is only available for the Chinese region.
ValueError: If the `login_ticket` argument is `None`, or if the `account_id` argument is `None`.
"""
if self.region != Region.CHINESE:
raise RuntimeError("This method is only available for the Chinese region.")
raise RegionNotSupported("This method is only available for the Chinese region.")
url = AUTH_URL.get_url(Region.CHINESE) / "getMultiTokenByLoginTicket"
login_ticket = login_ticket or self.cookies.get("login_ticket")
account_id = account_id or self.account_id
@ -82,11 +83,11 @@ class AuthClient(BaseClient):
Optional[str]: The retrieved cookie token (`cookie_token`).
Raises:
RuntimeError: This method is only available for the Chinese region.
RegionNotSupported: This method is only available for the Chinese region.
ValueError: If the `login_ticket` argument is `None`, or if the `account_id` argument is `None`.
"""
if self.region != Region.CHINESE:
raise RuntimeError("This method is only available for the Chinese region.")
raise RegionNotSupported("This method is only available for the Chinese region.")
stoken = stoken or self.cookies.get("stoken")
account_id = account_id or self.account_id
if stoken is None:
@ -121,11 +122,11 @@ class AuthClient(BaseClient):
Optional[str]: The retrieved cookie token (`cookie_token`).
Raises:
RuntimeError: This method is only available for the Chinese region.
RegionNotSupported: This method is only available for the Chinese region.
ValueError: If the `login_ticket` argument is `None`, or if the `account_id` argument is `None`.
"""
if self.region != Region.CHINESE:
raise RuntimeError("This method is only available for the Chinese region.")
raise RegionNotSupported("This method is only available for the Chinese region.")
stoken = stoken or self.cookies.get("stoken")
account_id = account_id or self.account_id
if stoken is None:
@ -158,11 +159,11 @@ class AuthClient(BaseClient):
Optional[str]: The authentication key, or None if not found.
Raises:
RuntimeError: This method is only available for the Chinese region.
RegionNotSupported: This method is only available for the Chinese region.
ValueError: If `stoken` is not found in the cookies or `player_id` not found.
"""
if self.region != Region.CHINESE:
raise RuntimeError("This method is only available for the Chinese region.")
raise RegionNotSupported("This method is only available for the Chinese region.")
stoken = self.cookies.get("stoken")
if stoken is None:
raise ValueError("stoken not found in cookies.")

View File

@ -6,6 +6,7 @@ from httpx import QueryParams
from simnet.client.base import BaseClient
from simnet.client.routes import REWARD_URL
from simnet.errors import GeetestTriggered
from simnet.models.lab.daily import DailyRewardInfo, DailyReward, ClaimedDailyReward
from simnet.utils.ds import hex_digest
from simnet.utils.enum_ import Game, Region
@ -219,7 +220,7 @@ class DailyRewardClient(BaseClient):
Returns:
If `reward` is True, a DailyReward object representing the claimed reward. Otherwise, None.
"""
await self.request_daily_reward(
daily_reward = await self.request_daily_reward(
"sign",
method="POST",
game=game or self.game,
@ -228,6 +229,17 @@ class DailyRewardClient(BaseClient):
validate=validate,
)
if self.region == Region.CHINESE and daily_reward.get("success", 0) == 1:
gt = daily_reward.get("gt", "")
challenge = daily_reward.get("challenge", "")
raise GeetestTriggered(gt, challenge)
if self.region == Region.OVERSEAS:
gt_result = daily_reward.get("gt_result")
if gt_result is not None and gt_result["success"] != 0:
gt = gt_result.get("gt", "")
challenge = gt_result.get("challenge", "")
raise GeetestTriggered(gt, challenge)
if not reward:
return None

View File

@ -3,6 +3,7 @@ from urllib.parse import urljoin
from httpx import URL as _URL
from simnet.errors import RegionNotSupported, NotSupported
from simnet.utils.enum_ import Region, Game
URLTypes = Union["URL", str]
@ -121,11 +122,11 @@ class InternationalRoute(BaseRoute):
URL: The URL for the given region.
Raises:
RuntimeError: If the given region is not supported.
RegionNotSupported: If the given region is not supported.
"""
if not self.urls[region]:
raise RuntimeError(f"URL does not support {region.name} region.")
raise RegionNotSupported(f"URL does not support {region.name} region.")
return self.urls[region]
@ -165,21 +166,21 @@ class GameRoute(BaseRoute):
URL: The URL for the given region and game.
Raises:
RuntimeError: If the given region or game is not supported.
RegionNotSupported: If the given region is not supported.
GameNotSupported: If the given game is not supported.
"""
if not self.urls[region]:
raise RuntimeError(f"URL does not support {region.name} region.")
raise RegionNotSupported(f"URL does not support {region.name} region.")
if not self.urls[region][game]:
raise RuntimeError(f"URL does not support {game.name} game for {region.name} region.")
raise NotSupported(f"URL does not support {game.name} game for {region.name} region.")
return self.urls[region][game]
PASSPORT_HOST = "passport-api.mihoyo.com"
RECORD_URL = InternationalRoute(
overseas="https://bbs-api-os.hoyolab.com/game_record",
chinese="https://api-takumi-record.mihoyo.com/game_record/app",
@ -263,5 +264,4 @@ YSULOG_URL = InternationalRoute(
HK4E_URL = Route("https://sg-hk4e-api.hoyoverse.com/common/hk4e_global/")
CODE_URL = Route("https://sg-hk4e-api.hoyoverse.com/common/apicdkey/api/webExchangeCdkey")

View File

@ -23,16 +23,27 @@ class BadRequest(ApiHelperException):
message (str): The formatted error message of the response.
"""
status_code: int = 200
ret_code: int = 0
original: str = ""
message: str = ""
def __init__(
self,
response: Optional[Dict[str, Any]] = None,
message: Optional[str] = None,
status_code: Optional[int] = None,
) -> None:
self.status_code = status_code or 0
self.ret_code = response.get("retcode", 0) if response else 0
self.original = response.get("message", "") if response else ""
self.message = message or self.original
if status_code is not None:
self.status_code = status_code
ret_code = response.get("ret_code")
if ret_code is not None:
self.ret_code = ret_code
response_message = response.get("message")
if response_message is not None:
self.original = response_message
if message is not None or self.original is not None:
self.message = message or self.original
display_code = self.ret_code or self.status_code
display_message = f"[{display_code}] {self.message}" if display_code else self.message
@ -139,6 +150,61 @@ class RedemptionCooldown(RedemptionException):
message = "Redemption is on cooldown."
class NeedChallenge(BadRequest):
"""Need to complete a captcha challenge."""
ret_code = 1034
message = "Need to complete a captcha challenge."
class GeetestTriggered(NeedChallenge):
"""Geetest triggered during daily reward claim."""
ret_code = 0
message = "Geetest triggered during daily reward claim."
def __init__(self, gt: str, challenge: str, *args, **kwargs):
super().__init__(*args, **kwargs)
self.gt = gt
self.challenge = challenge
class GeetestChallengeFailed(NeedChallenge):
"""Geetest challenge failed."""
message = "Geetest challenge failed."
class NotSupported(ApiHelperException):
"""API not supported."""
def __init__(self, message: str = "API not supported."):
super().__init__(message)
class RegionNotSupported(NotSupported):
"""API not supported for this region."""
def __init__(self, message: str = "API not supported for this region."):
super().__init__(message)
class GameNotSupported(NotSupported):
"""API not supported for this game."""
def __init__(self, message: str = "API not supported for this game."):
super().__init__(message)
class RequestNotSupported(BadRequest):
"""Service not supported for this request."""
ret_code = -520
def __init__(self, *args, **kwargs):
super().__init__(message="service not supported for this request.", *args, **kwargs)
class RedemptionClaimed(RedemptionException):
"""Redemption code has been claimed already."""
@ -191,9 +257,9 @@ _errors: Dict[int, Union[_TBR, str, Tuple[_TBR, Optional[str]]]] = {
# chinese
1008: AccountNotFound,
-1104: "This action must be done in the app.",
1034: NeedChallenge,
}
ERRORS: Dict[int, Tuple[_TBR, Optional[str]]] = {
ret_code: ((exc, None) if isinstance(exc, type) else (BadRequest, exc) if isinstance(exc, str) else exc)
for ret_code, exc in _errors.items()