Files
kami_itunes_third_api/src/cmd/scripts.py
danial b56184c673 refactor(deploy): 重构部署流程并添加容器锁机制
- 修改 Docker Compose 配置,简化网络设置
- 新增 Docker 入口脚本,实现容器锁机制
- 更新 Dockerfile,使用新的入口脚本
- 添加 Makefile,简化部署流程
- 优化 Python 脚本,去除冗余的循环结构
2024-12-19 00:44:56 +08:00

215 lines
8.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import pickle
import time
import traceback
from datetime import timedelta, datetime
from multiprocessing import Process
import redis
from loguru import logger
from src.database import redis_pool
from src.integrations.june.models.login import AppleAccountModel
from src.integrations.master_node.api import MasterNodeService
from src.integrations.master_node.models import (
RechargeQueryModel,
ItunesRedeemRequestModel,
)
from src.models.model import (
AppleAccountSchema,
LoginFailureResponse,
RedeemRequestModel,
)
from src.service.itunes import ItunesService
def run_redeem_task(
master_order: RechargeQueryModel,
master_node_service: MasterNodeService,
reties=3,
):
redis_conn = redis_pool.get_connection()
redis_client = redis.Redis(connection_pool=redis_conn)
try:
if reties <= 0:
logger.error(f"调用次数已用完,请重新检查订单:{master_order}")
master_node_service.update_order_status(
ItunesRedeemRequestModel(
order_no=master_order.orderNo,
status=30, # 这边的登录状态与apple_account_schema的status是一样的
remark="调用次数已用完,需要手动检查订单",
amount=0,
account_amount=0,
),
)
return
response_schema = None
redis_client.incrby(f"apple_account_{master_order.account}_count", 1)
while True:
response_schema_from_itunes = redis_client.get(
f"apple_account_{master_order.account}"
)
if not response_schema_from_itunes:
break
# 如果不存在
apple_account_schema = AppleAccountSchema.model_validate(
pickle.loads(response_schema_from_itunes)
)
logger.info(f"查找已存在Cookie信息{apple_account_schema.account}")
# 如果更新过账户密码
if (
apple_account_schema.account == master_order.account
and apple_account_schema.password != master_order.password
):
# 删除登录标识
redis_client.delete(f"apple_account_{master_order.account}")
break
if apple_account_schema.status != 2:
response_schema = apple_account_schema.login_schema
break
time.sleep(1)
itunes_service = ItunesService()
# 设置登录标识
if not response_schema_from_itunes:
redis_client.setex(
f"apple_account_{master_order.account}",
time=timedelta(seconds=30),
value=pickle.dumps(AppleAccountSchema(
account=master_order.account,
password=master_order.password,
status=2,
).model_dump()),
)
response_schema = itunes_service.login(
AppleAccountModel(
account=master_order.account, password=master_order.password
)
)
logger.info(f"登录完成:{master_order}")
if isinstance(response_schema, LoginFailureResponse):
# 如果登录失败,保存一天的登录信息
if not response_schema_from_itunes:
redis_client.setex(
f"apple_account_{master_order.account}",
time=timedelta(days=1),
value=pickle.dumps(AppleAccountSchema(
account=master_order.account,
password=master_order.password,
status=0,
login_schema=response_schema,
).model_dump()),
)
master_node_service.update_order_status(
ItunesRedeemRequestModel(
order_no=master_order.orderNo,
status=response_schema.status, # 这边的登录状态与apple_account_schema的status是一样的
remark=response_schema.message,
)
)
return
if not response_schema.login_schema.server_id:
return run_redeem_task(master_order, master_node_service, reties - 1)
if not response_schema_from_itunes:
# 登录成功保存9分钟的登录信息
redis_client.setex(
f"apple_account_{master_order.account}",
time=timedelta(minutes=9),
value=pickle.dumps(AppleAccountSchema(
account=master_order.account,
password=master_order.password,
status=1,
login_schema=response_schema,
).model_dump())
)
redeem_result = itunes_service.redeem(
master_order.cardPass,
RedeemRequestModel.model_validate(
{
**response_schema.model_dump(),
"account_name": master_order.account,
"order_no": master_order.orderNo,
"apple_card_login_log_id": response_schema.apple_card_login_log_id,
}
),
response_schema_from_itunes is not None,
)
# 需要登录
if redeem_result.status == 0:
redis_client.delete(f"apple_account_{master_order.account}")
return run_redeem_task(master_order, master_node_service, reties - 1)
if redeem_result.status == 40:
logger.warning("充值1分钟限制1分钟后重试")
time.sleep(60)
return run_redeem_task(master_order, master_node_service, reties - 1)
# 更新兑换状态
master_node_service.update_order_status(
ItunesRedeemRequestModel(
order_no=master_order.orderNo,
status=redeem_result.status, # 这边的登录状态与apple_account_schema的status是一样的
remark=redeem_result.remark,
amount=redeem_result.amount,
account_amount=redeem_result.balance,
),
)
except pickle.UnpicklingError as e:
logger.error(f"出现错误:{e},详细错误:\n{traceback.format_exc()}")
redis_client.delete(f"apple_account_{master_order.account}")
return run_redeem_task(master_order, master_node_service, reties - 1)
except Exception as e:
logger.error(f"出现错误:{e},详细错误:\n{traceback.format_exc()}")
master_node_service.update_order_status(
ItunesRedeemRequestModel(
order_no=master_order.orderNo,
status=30, # 这边的登录状态与apple_account_schema的status是一样的
remark="订单出错,请重新拉取",
amount=0,
account_amount=0,
),
)
finally:
redis_client.decrby(f"apple_account_{master_order.account}_count", 1)
# 如果程序正常结束,也需要执行清理操作
redis_client.close()
def run_task():
"""
执行任务
:return:
"""
# 注册信号处理程序
has_been_console = False
master_node_service = MasterNodeService()
# 1s获取两次订单
master_order = master_node_service.query_order()
if master_order.orderNo != "":
logger.info(f"当前订单:{master_order}")
run_redeem_task(master_order, master_node_service)
# 10分钟打印一次信息
if datetime.now().second % 10 == 0 and not has_been_console:
has_been_console = True
print(f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\t暂时没有订单")
if datetime.now().second % 10 != 0 and has_been_console:
has_been_console = False
def run():
# signal.signal(signal.SIGINT, signal_handler)
# signal.signal(signal.SIGTERM, signal_handler)
has_been_console = False
process = Process(target=run_task, args=(), daemon=True)
process.start()
while True:
# 10分钟打印一次信息
if datetime.now().minute % 2 == 0 and not has_been_console:
has_been_console = True
print(f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\t心跳正常 鲜橙状态:{process.is_alive()}",
flush=True, )
if datetime.now().minute % 2 != 0 and has_been_console:
has_been_console = False
if not process.is_alive():
process.close()
process = Process(target=run_task, args=(), daemon=True)
process.start()