104 lines
3.8 KiB
Python
104 lines
3.8 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
BOSS 账号 API:
|
||
- POST /api/accounts -> 前台添加账号时绑定到指定电脑
|
||
- POST /api/accounts/check -> 提交环境名称,自动派发 check_login 任务
|
||
- GET /api/accounts -> 查询所有账号登录状态
|
||
- GET /api/accounts/{worker_id} -> 查询指定 Worker 的账号状态
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
from typing import Optional
|
||
|
||
from fastapi import APIRouter, HTTPException
|
||
|
||
from common.protocol import TaskStatus, TaskType
|
||
from server.models import AccountBindRequest, CheckLoginRequest, TaskCreate
|
||
from server.core.worker_manager import worker_manager
|
||
from server.core.task_dispatcher import task_dispatcher
|
||
from server import db
|
||
|
||
router = APIRouter(prefix="/api/accounts", tags=["accounts"])
|
||
|
||
|
||
@router.post("", status_code=201)
|
||
async def bind_account(req: AccountBindRequest):
|
||
"""前台添加账号:保存账号环境与电脑绑定关系。"""
|
||
db.bind_account_to_worker(worker_id=req.worker_id, browser_name=req.browser_name)
|
||
return {"message": f"账号绑定已保存: {req.browser_name} -> {req.worker_id}"}
|
||
|
||
|
||
# ────────────────────────── 一键检测登录 ──────────────────────────
|
||
|
||
@router.post("/check", status_code=201)
|
||
async def check_login(req: CheckLoginRequest):
|
||
"""
|
||
前端提交:
|
||
{
|
||
"browser_name": "环境名称"
|
||
// 可选 "worker_id": "pc-1"
|
||
}
|
||
|
||
系统自动:
|
||
1. 如果请求没传 worker_id,则按已绑定关系查 worker_id
|
||
2. 派发 check_login 任务(Worker 会在比特浏览器中按名称查找该环境并打开)
|
||
3. 返回任务 ID,前端可轮询 GET /api/tasks/{task_id} 获取结果
|
||
"""
|
||
worker_id = req.worker_id
|
||
if not worker_id:
|
||
bind = db.get_account_by_name(req.browser_name)
|
||
if not bind:
|
||
raise HTTPException(
|
||
status_code=400,
|
||
detail=f"未找到账号绑定关系,请先调用 POST /api/accounts 绑定: {req.browser_name}",
|
||
)
|
||
worker_id = bind.get("worker_id")
|
||
|
||
# 检查 Worker 是否在线
|
||
if not worker_manager.is_online(worker_id):
|
||
raise HTTPException(status_code=503, detail=f"Worker {worker_id} 不在线")
|
||
|
||
# 创建 check_login 任务
|
||
task_req = TaskCreate(
|
||
task_type=TaskType.CHECK_LOGIN,
|
||
worker_id=worker_id,
|
||
account_name=req.browser_name,
|
||
params={"account_name": req.browser_name},
|
||
)
|
||
task = task_dispatcher.create_task(task_req)
|
||
|
||
# 通过 WebSocket 派发
|
||
ws = worker_manager.get_ws(worker_id)
|
||
if not ws:
|
||
task.status = TaskStatus.FAILED
|
||
task.error = "Worker WebSocket 连接不存在"
|
||
raise HTTPException(status_code=503, detail="Worker WebSocket 连接不存在")
|
||
|
||
success = await task_dispatcher.dispatch(task, ws.send_json)
|
||
if not success:
|
||
raise HTTPException(status_code=503, detail=f"任务派发失败: {task.error}")
|
||
|
||
worker_manager.set_current_task(worker_id, task.task_id)
|
||
|
||
return {
|
||
"message": f"检测任务已派发,环境: {req.browser_name},目标: {worker_id}",
|
||
"task_id": task.task_id,
|
||
"worker_id": worker_id,
|
||
}
|
||
|
||
|
||
# ────────────────────────── 查询账号状态 ──────────────────────────
|
||
|
||
@router.get("")
|
||
async def list_accounts(worker_id: Optional[str] = None):
|
||
"""查询 BOSS 账号登录状态列表。"""
|
||
if worker_id:
|
||
return db.get_accounts_by_worker(worker_id)
|
||
return db.get_all_accounts()
|
||
|
||
|
||
@router.get("/{worker_id}")
|
||
async def get_worker_accounts(worker_id: str):
|
||
"""查询指定 Worker 的所有账号状态。"""
|
||
return db.get_accounts_by_worker(worker_id)
|