refactor(june): 优化SixClient异步请求和异常处理
- SixClient中引入异步请求方法try_get_url获取并验证备用主机地址 - 初始化__base_url时支持异步调用,提升启动时灵活性 - _do_post与相关异步请求方法改用异常抛出替代返回None规范错误处理 - 修正部分解码逻辑,确保签名等字段的正确Base64和URL解码 - 代码中添加日志和重试机制以提升异常处理和调试能力 - 删除june模块中遗留的单元测试代码 - 调整june模型中字段类型,支持可选字符串以增强健壮性 - apps/apple/clients/itunes中添加Field默认值,防止字段缺失错误 - itunes解析XML相关函数增强健壮性,避免空指针异常 - core.clients.http_client支持完整http路径调用,注释掉自动抛错逻辑以兼容特殊响应 - base.py中retry_backoff类型显式定义为float,提高代码类型安全性
This commit is contained in:
@@ -31,14 +31,14 @@ class CustomSuccessData(BaseModel):
|
||||
|
||||
|
||||
class RedeemedCredit(BaseModel):
|
||||
movieRentalBalance: int
|
||||
songBalance: int
|
||||
videoBalance: int
|
||||
money: str
|
||||
totalCredit: str
|
||||
movieRentalBalance: int = Field(default=0)
|
||||
songBalance: int = Field(default=0)
|
||||
videoBalance: int = Field(default=0)
|
||||
money: str = Field(default="")
|
||||
totalCredit: str = Field(default="")
|
||||
moneyRaw: float = Field(default=0)
|
||||
gameBalance: int
|
||||
tvRentalBalance: int
|
||||
gameBalance: int = Field(default=0)
|
||||
tvRentalBalance: int = Field(default=0)
|
||||
|
||||
|
||||
class RedeemSuccessResponse(BaseModel):
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
from xml.etree import ElementTree
|
||||
from xml.etree.ElementTree import Element, fromstring
|
||||
|
||||
|
||||
def parse_xml(xml_str: str) -> dict:
|
||||
root = ElementTree.fromstring(xml_str)
|
||||
root = fromstring(xml_str)
|
||||
dict_data = {}
|
||||
key = ""
|
||||
for child in root.find("dict"):
|
||||
dict_element = root.find("dict")
|
||||
if dict_element is None:
|
||||
return dict_data
|
||||
for child in dict_element:
|
||||
if child.tag == "key":
|
||||
key = child.text
|
||||
key = child.text or ""
|
||||
else:
|
||||
if child.tag == "integer":
|
||||
dict_data[key] = int(child.text)
|
||||
dict_data[key] = int(child.text or "0")
|
||||
elif child.tag == "string":
|
||||
dict_data[key] = child.text if child.text else ""
|
||||
elif child.tag == "true":
|
||||
@@ -24,12 +27,12 @@ def parse_xml(xml_str: str) -> dict:
|
||||
return dict_data
|
||||
|
||||
|
||||
def parse_xml_tree(tree_list: list[ElementTree]):
|
||||
def parse_xml_tree(tree_list: list[Element]):
|
||||
dict_data = {}
|
||||
key = ""
|
||||
for child in tree_list:
|
||||
if child.tag == "key":
|
||||
key = child.text
|
||||
key = child.text or ""
|
||||
else:
|
||||
if child.tag == "string":
|
||||
dict_data[key] = child.text if child.text else ""
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import asyncio
|
||||
import base64
|
||||
import hashlib
|
||||
import json
|
||||
@@ -24,11 +25,48 @@ from core.clients.http_client import HTTPClient
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class SixClient:
|
||||
async def try_get_url() -> str:
|
||||
host_items = ["https://gitee.com/liuyueapp/blogsLiuyue/raw/master/assets/aphos.css", "https://meixi2.oss-us-west-1.aliyuncs.com/host.txt", "https://zjzhuanfa.oss-cn-shenzhen.aliyuncs.com/host.txt"]
|
||||
target_host_urls = []
|
||||
for host in host_items:
|
||||
client = HTTPClient(
|
||||
base_url=host,
|
||||
timeout=2.0,
|
||||
max_retries=1,
|
||||
)
|
||||
try:
|
||||
response = await client.get(host)
|
||||
if response.status_code == 200:
|
||||
target_host_urls.extend(response.text.splitlines())
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
# 去重
|
||||
target_host_urls = list(set(target_host_urls))
|
||||
for host in target_host_urls:
|
||||
client = HTTPClient(
|
||||
base_url=host,
|
||||
timeout=5.0,
|
||||
max_retries=1,
|
||||
)
|
||||
try:
|
||||
response = await client.get(host+"/AppleClientApi/requestApi")
|
||||
if response.status_code == 404:
|
||||
return host
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return "http://43.240.73.119:6113"
|
||||
|
||||
|
||||
__base_url = asyncio.run(main=try_get_url())
|
||||
|
||||
class SixClient:
|
||||
__base_url = "http://43.240.73.119:6113"
|
||||
|
||||
def __init__(self):
|
||||
self.__base_url = "http://43.240.73.119:6113"
|
||||
if not self.__base_url:
|
||||
self.__base_url = asyncio.run(try_get_url())
|
||||
self._client: Optional[HTTPClient] = None
|
||||
|
||||
|
||||
async def _get_client(self) -> HTTPClient:
|
||||
"""获取或创建HTTP客户端"""
|
||||
if self._client is None:
|
||||
@@ -38,7 +76,7 @@ class SixClient:
|
||||
max_retries=3,
|
||||
)
|
||||
return self._client
|
||||
|
||||
|
||||
async def close(self):
|
||||
"""关闭客户端连接"""
|
||||
if self._client:
|
||||
@@ -47,10 +85,9 @@ class SixClient:
|
||||
|
||||
async def _do_post(
|
||||
self, post_data: Any, type_: str, start_now_fun: str = "0", reties: int = 3
|
||||
) -> AppleSixResponseModel | None:
|
||||
) -> AppleSixResponseModel:
|
||||
if reties <= 0:
|
||||
return None
|
||||
|
||||
raise Exception("请求超时")
|
||||
client = await self._get_client()
|
||||
|
||||
req_count = random.randint(0, 90) + 1
|
||||
@@ -154,14 +191,14 @@ class SixClient:
|
||||
if response and response.Data:
|
||||
response.Data = json.loads(response.Data)
|
||||
return AppleSixResponseModel[dict].model_validate(response.model_dump())
|
||||
return None
|
||||
raise Exception("远程登录失败")
|
||||
|
||||
async def get_sign_sap_setup(
|
||||
self, reties: int = 3
|
||||
) -> AppleSixResponseModel[LoginSignatureModel] | None:
|
||||
) -> AppleSixResponseModel[LoginSignatureModel]:
|
||||
if reties < 0:
|
||||
return None
|
||||
response = await self._do_post(
|
||||
raise Exception("获取 sign 失败")
|
||||
response: AppleSixResponseModel[str] = await self._do_post(
|
||||
json.dumps(
|
||||
{
|
||||
"gZip": "1",
|
||||
@@ -174,20 +211,23 @@ class SixClient:
|
||||
start_now_fun="9",
|
||||
)
|
||||
if not response or not response.Data:
|
||||
return None
|
||||
response.Data = json.loads(decode_and_decompress(response.Data))
|
||||
if response.Data.get("msg") == "请重试":
|
||||
raise Exception("获取 sign 失败")
|
||||
response_data = json.loads(decode_and_decompress(response.Data))
|
||||
if response_data.get("msg") == "请重试":
|
||||
logger.info(f"重试六月登录,{response}")
|
||||
time.sleep(1)
|
||||
return await self.get_sign_sap_setup(reties - 1)
|
||||
response = AppleSixResponseModel[LoginSignatureModel].model_validate(
|
||||
response.model_dump()
|
||||
|
||||
target_response_data = response.model_dump()
|
||||
target_response_data["Data"] = response_data
|
||||
target_response = AppleSixResponseModel[LoginSignatureModel].model_validate(
|
||||
target_response_data
|
||||
)
|
||||
# 处理signature编码问题和Base64转码问题
|
||||
response.Data.signature = base64.b64decode(
|
||||
parse.unquote_plus(response.Data.signature)
|
||||
target_response.Data.signature = base64.b64decode(
|
||||
parse.unquote_plus(target_response.Data.signature)
|
||||
).decode()
|
||||
return response
|
||||
return target_response
|
||||
|
||||
async def get_sign_sap_setup_cert(
|
||||
self,
|
||||
@@ -195,10 +235,10 @@ class SixClient:
|
||||
sign: AppleSixResponseModel[LoginSignatureModel],
|
||||
sign_sap_setup: str,
|
||||
reties: int = 3,
|
||||
) -> AppleSixResponseModel[AuthenticateModel] | None:
|
||||
) -> AppleSixResponseModel[AuthenticateModel]:
|
||||
if reties < 0:
|
||||
return None
|
||||
response = await self._do_post(
|
||||
raise Exception("获取 sign 失败")
|
||||
response:AppleSixResponseModel[str] = await self._do_post(
|
||||
json.dumps(
|
||||
{
|
||||
"signSap": parse.quote_plus(
|
||||
@@ -220,23 +260,28 @@ class SixClient:
|
||||
start_now_fun="9",
|
||||
)
|
||||
if not response or not response.Data:
|
||||
return None
|
||||
raise Exception("获取 sign 失败")
|
||||
try:
|
||||
response.Data = json.loads(decode_and_decompress(response.Data))
|
||||
response_data = json.loads(decode_and_decompress(response.Data))
|
||||
except AttributeError as e:
|
||||
logger.error(f"获取cert失败,{response},错误信息:{traceback.format_exc()}")
|
||||
logger.error(msg=f"获取cert失败,{response},错误信息:{traceback.format_exc()}")
|
||||
return await self.get_sign_sap_setup_cert(account, sign, sign_sap_setup, reties - 1)
|
||||
if response.Data.get("msg") == "请重试":
|
||||
if response_data.get("msg") == "请重试":
|
||||
logger.info(f"重试六月登录,{response}")
|
||||
time.sleep(1)
|
||||
return await self.get_sign_sap_setup_cert(
|
||||
account, sign, sign_sap_setup, reties - 1
|
||||
)
|
||||
response = AppleSixResponseModel[AuthenticateModel].model_validate(
|
||||
|
||||
|
||||
new_target_response_data= response.model_dump()
|
||||
new_target_response_data["Data"] = response_data
|
||||
target_response_data = AppleSixResponseModel[AuthenticateModel].model_validate(
|
||||
response.model_dump()
|
||||
)
|
||||
# 解码数据
|
||||
response.Data.signature = parse.unquote_plus(response.Data.signature)
|
||||
response.Data.guid = parse.unquote_plus(response.Data.guid)
|
||||
response.Data.post = parse.unquote_plus(response.Data.post)
|
||||
return response
|
||||
target_response_data.Data.signature = parse.unquote_plus(target_response_data.Data.signature)
|
||||
target_response_data.Data.guid = parse.unquote_plus(target_response_data.Data.guid)
|
||||
target_response_data.Data.post = parse.unquote_plus(target_response_data.Data.post)
|
||||
return target_response_data
|
||||
|
||||
|
||||
@@ -26,22 +26,22 @@ class LoginSessionInfo(BaseModel):
|
||||
|
||||
|
||||
class Cookies(BaseModel):
|
||||
wosid: str = Field(None, alias="wosid")
|
||||
woinst: str = Field(None, alias="woinst")
|
||||
wosid: str | None = Field(None, alias="wosid")
|
||||
woinst: str | None = Field(None, alias="woinst")
|
||||
ns_mzf_inst: str = Field(..., alias="ns-mzf-inst")
|
||||
mzf_in: str = Field(None, alias="mzf_in")
|
||||
mzf_dr: str = Field(None, alias="mzf_dr")
|
||||
hsaccnt: str = Field(None, alias="hsaccnt")
|
||||
mzf_in: str | None = Field(None, alias="mzf_in")
|
||||
mzf_dr: str | None = Field(None, alias="mzf_dr")
|
||||
hsaccnt: str | None = Field(None, alias="hsaccnt")
|
||||
session_store_id: str = Field(..., alias="session-store-id")
|
||||
X_Dsid: str = Field(..., alias="X-Dsid")
|
||||
mz_at0_135096725: str = Field(..., alias="mz_at0-135096725")
|
||||
ampsc: str = Field(None, alias="ampsc")
|
||||
ampsc: str | None = Field(None, alias="ampsc")
|
||||
mz_at_ssl_135096725: str = Field(..., alias="mz_at_ssl-135096725")
|
||||
mz_at_mau_135096725: str = Field(..., alias="mz_at_mau-135096725")
|
||||
pldfltcid: str = Field(None, alias="pldfltcid")
|
||||
pldfltcid: str | None = Field(None, alias="pldfltcid")
|
||||
tv_pldfltcid: str = Field(..., alias="tv-pldfltcid")
|
||||
wosid_lite: str = Field(..., alias="wosid-lite")
|
||||
itspod: str = Field(None, alias="itspod")
|
||||
itspod: str | None = Field(None, alias="itspod")
|
||||
|
||||
|
||||
class RemoteCookieModel(BaseModel):
|
||||
@@ -87,7 +87,7 @@ DataT = TypeVar("DataT")
|
||||
class AppleSixResponseModel(BaseModel, Generic[DataT]):
|
||||
Code: str = Field(default="")
|
||||
Message: str = Field(default="")
|
||||
Data: DataT = Field(default="")
|
||||
Data: DataT = Field()
|
||||
serverIndex: int = Field(default=0)
|
||||
extend: str = Field(default="")
|
||||
authenUserInfo: str = Field(default="")
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
from unittest import TestCase
|
||||
|
||||
from src.integrations.june.api import SixClient
|
||||
|
||||
|
||||
class TestSixClient(TestCase):
|
||||
def test_get_sign_sap_setup(self):
|
||||
result = SixClient().get_sign_sap_setup()
|
||||
print(result)
|
||||
@@ -1,13 +0,0 @@
|
||||
from unittest import TestCase
|
||||
|
||||
from src.integrations.june.utils.utils import ShareCodeUtils, MachineCode
|
||||
|
||||
|
||||
class TestShareCodeUtils(TestCase):
|
||||
def test_code_to_id(self):
|
||||
print(ShareCodeUtils.code_to_id("2JPA"))
|
||||
|
||||
def test_get_cpu_info(self):
|
||||
print(MachineCode().get_cpu_info())
|
||||
print(MachineCode().get_hd_id())
|
||||
print(MachineCode().get_mo_address())
|
||||
Reference in New Issue
Block a user