WechatOnCloud/bridge/woc_bridge/routes/status.py
Kris 102b98adea refactor: 完成项目包结构重构与基础模块搭建
本次提交将woc-bridge项目重构为模块化包结构,按职责拆分多个子域:
1. 新增models层定义所有Pydantic数据模型与统一错误体系
2. 拆分db/ui/messaging/routes等业务域模块
3. 实现基础API路由:状态查询、截图、登录、媒体获取等
4. 重构tools脚本的模块导入路径
5. 补充版本号与能力清单定义
6. 完善全局配置与依赖管理

整体完成项目从单文件脚本到可维护的包结构迁移,为后续功能开发打下基础。
2026-07-08 23:25:58 +08:00

100 lines
4.1 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.

from __future__ import annotations
import asyncio
import logging
import time
from fastapi import APIRouter
from woc_bridge.config import _state, _require_xdotool, _require_db_reader
from woc_bridge.db.coordinator import with_db_retry, _resolve_db_state
from woc_bridge.models import StatusResponse
from woc_bridge.version import BRIDGE_VERSION, BRIDGE_CAPABILITIES, MEDIA_SUPPORTED
logger = logging.getLogger("woc-bridge")
router = APIRouter()
@router.get("/api/status", response_model=StatusResponse)
@with_db_retry
async def get_status() -> StatusResponse:
"""聚合返回 bridge 运行状态。
一次请求内完成 4 类检测进程运行、窗口存在、登录态、DB 可达性,
并返回当前账号信息与客户端轮询建议参数。所有调用方channels 适配器、
面板健康检查、诊断 autofix都应优先调本接口判断前置条件。
Returns:
StatusResponse含 bridge_version / wechat_running / wechat_window_found
/ login_state / db_accessible / current_wxid / current_nickname
/ uptime_seconds / display / max_batch_size / poll_interval_ms
Notes:
- 不抛业务错误:即使微信未运行 / DB 加密,也返回 200 + 对应 false 字段,
让调用方按字段判定下一步动作(而非按 HTTP 状态码)
- login_state 内联判定(不调 detect_login_state避免重复 pgrep/xdotool
- DB 加密时细分:有 key 且验证过 → encrypted_key_ok + db_accessible=true
无 key 且自动提取未启用 → encrypted_no_key
自动提取已尝试但失败 → key_extract_failed
二者 db_accessible 均为 false
- current_wxid/nickname 仅在 db_accessible=true 且 login_state=logged_in
时才尝试读 DB失败静默为空字符串
"""
xdotool = _require_xdotool()
db_reader = _require_db_reader()
# 一次 status 请求内复用 pgrep/xdotool 结果,避免重复调用
wechat_running = await xdotool.is_wechat_running()
window_id = await xdotool.find_wechat_window() if wechat_running else None
wechat_window_found = window_id is not None
# 登录态内联判定,避免 detect_login_state 内部再次 pgrep/xdotool search
if not wechat_running:
login_state = "not_running"
elif not wechat_window_found:
login_state = "not_logged_in"
else:
login_state = "logged_in"
# DB 状态:统一走 _resolve_db_state不触发自动提取仅解析
db_state = await _resolve_db_state()
db_accessible = db_state.db_accessible
db_error_code = db_state.db_error_code
init_in_progress = _state.init_state.state == "running"
init_progress_pct = _state.init_state.progress_pct
init_message = _state.init_state.message
# current_wxid / current_nickname从 DB 读,失败为空
current_wxid = ""
current_nickname = ""
if db_accessible and login_state == "logged_in":
try:
self_info = await asyncio.to_thread(db_reader.get_self_info)
current_wxid = self_info.get("wxid", "")
current_nickname = self_info.get("nickname", "")
except Exception:
current_wxid = ""
current_nickname = ""
uptime_seconds = time.monotonic() - _state.start_time
return StatusResponse(
bridge_version=BRIDGE_VERSION,
wechat_running=wechat_running,
wechat_window_found=wechat_window_found,
login_state=login_state,
db_accessible=db_accessible,
db_error_code=db_error_code,
init_in_progress=init_in_progress,
init_progress_pct=init_progress_pct,
init_message=init_message,
current_wxid=current_wxid,
current_nickname=current_nickname,
uptime_seconds=uptime_seconds,
display=_state.config.display,
max_batch_size=_state.config.max_batch_size,
poll_interval_ms=_state.config.poll_interval_ms,
send_queue_pending=_state.send_queue.pending_count() if _state.send_queue else 0,
media_supported=MEDIA_SUPPORTED,
bridge_capabilities=list(BRIDGE_CAPABILITIES),
)