66 lines
2.2 KiB
Python
66 lines
2.2 KiB
Python
from enum import StrEnum
|
|
|
|
|
|
class AlipayErrorCode(StrEnum):
|
|
SIGN_FAILED = "sign_failed"
|
|
VERIFY_FAILED = "verify_failed"
|
|
AUTH_FAILED = "auth_failed"
|
|
RATE_LIMITED = "rate_limited"
|
|
OUT_OF_WINDOW = "out_of_window"
|
|
DAILY_LIMIT_EXCEEDED = "daily_limit_exceeded"
|
|
USER_NOT_FOLLOWED = "user_not_followed"
|
|
MSG_TOO_LONG = "msg_too_long"
|
|
NETWORK_ERROR = "network_error"
|
|
BUSINESS_ERROR = "business_error"
|
|
UNKNOWN = "unknown"
|
|
|
|
|
|
class AlipayError(Exception):
|
|
def __init__(
|
|
self,
|
|
code: AlipayErrorCode,
|
|
message: str = "",
|
|
sub_code: str = "",
|
|
sub_msg: str = "",
|
|
retryable: bool = False,
|
|
retry_after: float | None = None,
|
|
):
|
|
self.code = code
|
|
self.message = message
|
|
self.sub_code = sub_code
|
|
self.sub_msg = sub_msg
|
|
self.retryable = retryable
|
|
self.retry_after = retry_after
|
|
super().__init__(f"[{code}] {message}" + (f" | {sub_code}: {sub_msg}" if sub_code else ""))
|
|
|
|
|
|
_ERROR_CLASSIFICATION: dict[str, tuple[AlipayErrorCode, bool]] = {
|
|
"40001": (AlipayErrorCode.SIGN_FAILED, False),
|
|
"40002": (AlipayErrorCode.VERIFY_FAILED, False),
|
|
"40004": (AlipayErrorCode.BUSINESS_ERROR, False),
|
|
"40006": (AlipayErrorCode.AUTH_FAILED, False),
|
|
"20000": (AlipayErrorCode.NETWORK_ERROR, True),
|
|
"20001": (AlipayErrorCode.AUTH_FAILED, False),
|
|
}
|
|
|
|
_SUB_CODE_CLASSIFICATION: dict[str, tuple[AlipayErrorCode, bool]] = {
|
|
"isv.invalid-signature": (AlipayErrorCode.SIGN_FAILED, False),
|
|
"isv.invalid-app-id": (AlipayErrorCode.VERIFY_FAILED, False),
|
|
"isv.message-count-per-day-isv-error": (AlipayErrorCode.DAILY_LIMIT_EXCEEDED, False),
|
|
"isv.invalid-auth-token": (AlipayErrorCode.AUTH_FAILED, False),
|
|
"isv.business-fail": (AlipayErrorCode.USER_NOT_FOLLOWED, False),
|
|
}
|
|
|
|
|
|
def classify_alipay_error(code: str, sub_code: str = "") -> tuple[AlipayErrorCode, bool]:
|
|
if sub_code and sub_code in _SUB_CODE_CLASSIFICATION:
|
|
return _SUB_CODE_CLASSIFICATION[sub_code]
|
|
if code in _ERROR_CLASSIFICATION:
|
|
return _ERROR_CLASSIFICATION[code]
|
|
return (AlipayErrorCode.UNKNOWN, False)
|
|
|
|
|
|
def is_retryable_error(code: str, sub_code: str = "") -> bool:
|
|
_, retryable = classify_alipay_error(code, sub_code)
|
|
return retryable
|