140 lines
4.9 KiB
Python
140 lines
4.9 KiB
Python
"""登录服务:复用 douyu/ 核心模块,在线程池中执行登录并推送日志。"""
|
|
|
|
import asyncio
|
|
import threading
|
|
import time
|
|
import uuid
|
|
from datetime import datetime
|
|
from typing import Optional
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
from core.douyu import DouyuLogin
|
|
from core.models import Account, ProxyConfig as DouyuProxyConfig
|
|
from ..models import Account as AccountModel, LoginTask, ProxyConfig as ProxyConfigModel
|
|
from ..permissions import has_permission
|
|
|
|
|
|
class LoginBatchRunner:
|
|
"""批量登录执行器,在线程中运行,通过 asyncio.Queue 推送日志。"""
|
|
|
|
def __init__(
|
|
self,
|
|
db: Session,
|
|
account_ids: list[int],
|
|
created_by: int,
|
|
creator_role: str,
|
|
max_geetest_retries: int = 5,
|
|
proxy_config: Optional[ProxyConfigModel] = None,
|
|
log_queue: Optional[asyncio.Queue] = None,
|
|
loop: Optional[asyncio.AbstractEventLoop] = None,
|
|
):
|
|
self.db = db
|
|
self.account_ids = account_ids
|
|
self.created_by = created_by
|
|
self.creator_role = creator_role
|
|
self.max_geetest_retries = max_geetest_retries
|
|
self.proxy_config = proxy_config
|
|
self.log_queue = log_queue
|
|
self.loop = loop
|
|
self.batch_id = uuid.uuid4().hex[:12]
|
|
self._stop = threading.Event()
|
|
|
|
def stop(self):
|
|
self._stop.set()
|
|
|
|
def _push_log(self, level: str, message: str):
|
|
if self.log_queue and self.loop:
|
|
asyncio.run_coroutine_threadsafe(
|
|
self.log_queue.put({"level": level, "message": message}),
|
|
self.loop,
|
|
)
|
|
|
|
def run(self):
|
|
"""在线程中执行批量登录。"""
|
|
batch_id = self.batch_id
|
|
self._push_log("info", f"批量登录任务 {batch_id} 开始,共 {len(self.account_ids)} 个账号")
|
|
|
|
# 创建任务记录
|
|
tasks = []
|
|
for aid in self.account_ids:
|
|
acc = self.db.query(AccountModel).filter(AccountModel.id == aid).first()
|
|
if not acc:
|
|
continue
|
|
# 权限检查:客服只能跑分配给自己的
|
|
if not has_permission(self.creator_role, "login:view_all"):
|
|
if acc.assigned_to != self.created_by:
|
|
self._push_log("warning", f"跳过无权账号: {acc.username}")
|
|
continue
|
|
|
|
task = LoginTask(
|
|
batch_id=batch_id,
|
|
account_id=aid,
|
|
status="pending",
|
|
created_by=self.created_by,
|
|
)
|
|
self.db.add(task)
|
|
tasks.append((task, acc))
|
|
|
|
self.db.commit()
|
|
|
|
# 构建代理配置
|
|
proxy_url = None
|
|
proxy_api_url = None
|
|
if self.proxy_config and self.proxy_config.enabled:
|
|
if self.proxy_config.http or self.proxy_config.https:
|
|
proxy_url = {
|
|
'http': self.proxy_config.http or self.proxy_config.https,
|
|
'https': self.proxy_config.https or self.proxy_config.http,
|
|
}
|
|
elif self.proxy_config.api_url:
|
|
proxy_api_url = self.proxy_config.api_url
|
|
|
|
for i, (task, acc) in enumerate(tasks):
|
|
if self._stop.is_set():
|
|
self._push_log("warning", "任务已停止")
|
|
break
|
|
|
|
task.status = "running"
|
|
self.db.commit()
|
|
|
|
self._push_log("info", f"[{i+1}/{len(tasks)}] 开始登录: {acc.username}")
|
|
|
|
try:
|
|
account = Account(
|
|
username=acc.username,
|
|
password=acc.password,
|
|
email=acc.email,
|
|
email_password=acc.email_password,
|
|
email_imap_server=acc.email_imap_server or "",
|
|
email_imap_port=acc.email_imap_port or 993,
|
|
)
|
|
|
|
loginer = DouyuLogin(
|
|
account,
|
|
proxy=proxy_url,
|
|
proxy_api_url=proxy_api_url,
|
|
max_geetest_retries=self.max_geetest_retries,
|
|
)
|
|
result = loginer.login()
|
|
|
|
if result.success:
|
|
task.status = "success"
|
|
task.cookie = result.cookie
|
|
task.message = "登录成功"
|
|
self._push_log("success", f"[{i+1}] {acc.username} 登录成功")
|
|
else:
|
|
task.status = "failed"
|
|
task.message = result.message
|
|
self._push_log("error", f"[{i+1}] {acc.username} 登录失败: {result.message}")
|
|
|
|
except Exception as e:
|
|
task.status = "error"
|
|
task.message = str(e)
|
|
self._push_log("error", f"[{i+1}] {acc.username} 登录异常: {e}")
|
|
|
|
task.finished_at = datetime.utcnow()
|
|
self.db.commit()
|
|
|
|
self._push_log("info", f"批量登录任务 {batch_id} 完成")
|