Files
boss_dp/server/api/accounts.py
Your Name 2cfbc179ba 哈哈
2026-02-12 17:23:34 +08:00

122 lines
4.4 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.

# -*- 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, Request
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"])
async def _parse_body(request: Request) -> dict:
"""
兼容两种请求体:
1) application/json
2) multipart/form-data 或 x-www-form-urlencoded
"""
ctype = (request.headers.get("content-type") or "").lower()
if "application/json" in ctype:
data = await request.json()
if not isinstance(data, dict):
raise HTTPException(status_code=422, detail="JSON body 必须是对象")
return data
form = await request.form()
return dict(form)
@router.post("", status_code=201)
async def bind_account(request: Request):
"""前台添加账号:保存账号环境与电脑绑定关系。"""
req = AccountBindRequest(**(await _parse_body(request)))
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(request: Request):
"""
前端提交:
{
"browser_name": "环境名称"
// 可选 "worker_id": "pc-1"
}
系统自动:
1. 如果请求没传 worker_id则按已绑定关系查 worker_id
2. 派发 check_login 任务Worker 会在比特浏览器中按名称查找该环境并打开)
3. 返回任务 ID前端可轮询 GET /api/tasks/{task_id} 获取结果
"""
req = CheckLoginRequest(**(await _parse_body(request)))
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)