19 KiB
19 KiB
WXAuto Center 开发指南
开发环境搭建
环境要求
- Python 3.8+
- Node.js 14+ (可选,用于前端开发)
- Git
克隆与安装
# 克隆项目
git clone <repository-url>
cd wxauto_api/wxauto_center
# 创建虚拟环境(推荐)
python -m venv venv
source venv/bin/activate # Linux/Mac
# 或 venv\Scripts\activate # Windows
# 安装依赖
pip install -r requirements.txt
配置开发环境
# 复制环境变量示例文件
cp .env.example .env
# 编辑 .env 文件
vim .env
启动开发服务器
# 方式1:使用 run.py(推荐)
python run.py
# 方式2:单进程开发模式
python run.py --reload
# 方式3:使用 uvicorn
uvicorn main:app --host 0.0.0.0 --port 8080 --reload
# 方式4:多进程模式(需要 Redis)
python run.py --workers 4
访问服务
- 主界面:http://localhost:8080/static/index.html
- API 文档:http://localhost:8080/docs
- ReDoc:http://localhost:8080/redoc
项目结构详解
目录结构
wxauto_center/
├── main.py # FastAPI 应用入口
├── run.py # 多进程启动脚本
├── config.py # 配置管理模块
├── api/ # API 路由目录
│ ├── __init__.py
│ ├── nodes.py # 节点管理 API
│ ├── messages.py # 消息发送 API
│ ├── external.py # 外部扩展 API
│ ├── callback.py # 回调接口 API
│ └── plugins.py # 插件管理 API
├── services/ # 业务逻辑目录
│ ├── __init__.py
│ ├── node_manager.py # 节点管理器
│ ├── monitor_service.py # 监控服务
│ ├── log_service.py # 日志服务(支持Redis+文件持久化)
│ └── queue_service.py # 消息队列服务(支持Redis后端)
├── plugins/ # 插件目录
│ ├── __init__.py
│ ├── base.py # 插件基类
│ └── builtin.py # 内置插件
├── models/ # 数据模型目录
├── utils/ # 工具函数目录
├── static/ # 静态文件目录
│ ├── index.html # 主页面
│ ├── css/ # 样式目录
│ └── js/ # JavaScript 目录
├── logs/ # 日志目录
│ └── app.log # 应用日志
├── config.json # 配置文件
└── requirements.txt # 依赖列表
代码架构说明
主入口 (main.py)
main.py 是 FastAPI 应用的入口文件,负责:
- 初始化 FastAPI 应用
- 配置 CORS 中间件
- 注册路由(nodes, messages, external, plugins)
- 处理启动/关闭事件
关键代码流程:
# 启动事件
@app.on_event("startup")
async def startup_event():
load_config_from_file("config.json") # 加载配置
register_builtin_plugins() # 注册内置插件
for node_data in config_manager.get_all_nodes():
await node_manager.add_node(...) # 添加节点
await monitor_service.start() # 启动监控服务
# 关闭事件
@app.on_event("shutdown")
async def shutdown_event():
await monitor_service.stop() # 停止监控
save_config_to_file("config.json") # 保存配置
配置管理 (config.py)
采用 Pydantic Settings 进行配置管理:
# 配置模型
Settings # 主配置类
NodeConfig # 节点配置
PluginConfig # 插件配置
WebhookConfig # Webhook 配置
MonitorConfig # 监控配置
# 配置管理器
ConfigManager # 提供节点配置的增删改查
# 配置加载/保存
load_config_from_file() # 从文件加载
save_config_to_file() # 保存到文件
节点管理器 (services/node_manager.py)
NodeManager 是核心服务类,负责与 WXAuto-HTTP-API 节点通信。
# 节点状态
class NodeStatus:
ACTIVE = "active" # API 可用
INACTIVE = "inactive" # API 不可用
ERROR = "error" # API 错误
# 节点类
class Node:
node_id: str # 节点唯一标识
name: str # 节点显示名称
api_url: str
api_key: str
description: str
group: str
enabled: bool
status: str # NodeStatus
wechat_status: str
is_healthy: bool
health_message: str
# NodeManager 方法
class NodeManager:
async def add_node(...) # 添加节点
async def remove_node(node_id) # 删除节点
async def get_node(node_id) # 获取单个节点
async def get_all_nodes() # 获取所有节点
async def get_enabled_nodes() # 获取已启用节点
async def get_nodes_by_group() # 按分组获取节点
async def update_node(node_id, **kwargs) # 更新节点
async def check_node_status(node_id) # 检查节点状态
async def is_node_healthy(node_id) # 检查节点健康状态
async def send_message(node_id, who, msg, msg_type) # 发送消息
async def send_message_to_group(node_id, group_name, msg, msg_type) # 发送群消息
async def get_friends_list(node_id) # 获取好友列表
async def get_groups_list(node_id) # 获取群列表
async def get_messages(node_id, chat_name, limit) # 获取消息历史
**注意**:已移除 `broadcast_message()` 方法,广播功能不再支持。
### 监控服务 (services/monitor_service.py)
`MonitorService` 负责定时检测节点和微信状态。
```python
class MonitorService:
async def start() # 启动监控
async def stop() # 停止监控
async def _monitor_loop() # 主监控循环
async def _check_all_nodes() # 检查所有节点
async def _check_node(node_id) # 检查单个节点
async def _send_webhook(event, data) # 发送Webhook通知
def get_last_status(node_id) # 获取最后状态
def get_all_status() # 获取所有状态
日志服务 (services/log_service.py)
LogService 提供日志记录和实时推送功能。
class LogService:
def __init__(self, max_logs=500):
self.max_logs = max_logs
self._logs: deque = deque(maxlen=max_logs) # 限制500条
self._subscribers: List[asyncio.Queue] = []
# 日志方法
def info/warning/error/success(message, source)
# SSE 订阅
async def subscribe() -> asyncio.Queue # 订阅日志流
def unsubscribe(queue) # 取消订阅
# 日志查询
def get_recent_logs(count) # 获取最近日志
def get_all_logs() # 获取所有日志
插件开发指南
插件架构
系统采用插件化设计,支持扩展:
PluginBase (抽象基类)
├── MessageHandlerPlugin
├── DataSourcePlugin
├── ActionTriggerPlugin
└── AIAgentPlugin
开发自定义插件
1. 创建插件类
# my_plugin.py
from plugins.base import PluginBase, PluginType
class MyCustomPlugin(PluginBase):
plugin_name = "my_custom_plugin"
plugin_version = "1.0.0"
plugin_type = PluginType.CUSTOM
plugin_description = "我的自定义插件"
def initialize(self, config: Dict[str, Any]) -> bool:
self.config = config
# 初始化逻辑
return True
def execute(self, params: Dict[str, Any]) -> Dict[str, Any]:
# 插件逻辑
return {"success": True, "result": "done"}
2. 注册插件
# 在 builtin.py 或 main.py 中注册
from plugins.base import PluginRegistry
my_plugin = MyCustomPlugin()
my_plugin.initialize({"key": "value"})
PluginRegistry.register(my_plugin)
插件类型详解
DataSourcePlugin
用于从外部数据源获取数据:
class MyDataSourcePlugin(DataSourcePlugin):
plugin_name = "my_data_source"
def fetch_data(self, query: str, params: Dict[str, Any]) -> List[Dict[str, Any]]:
# 获取数据逻辑
return [...]
AIAgentPlugin
用于 AI 消息处理:
class MyAIAgentPlugin(AIAgentPlugin):
plugin_name = "my_ai_agent"
def process(self, input_text: str, context: Dict[str, Any]) -> str:
# 处理输入,返回 AI 回复
return "AI 回复"
def get_response(self, messages: List[Dict[str, str]]) -> str:
# 获取对话响应
return "AI 回复"
API 调用示例
使用 Python 调用
import httpx
API_KEY = "your-external-api-key"
BASE_URL = "http://localhost:8080/api/v1"
headers = {
"X-API-Key": API_KEY,
"Content-Type": "application/json"
}
# 添加节点
response = httpx.post(
f"{BASE_URL}/nodes",
json={
"node_id": "wx1",
"name": "微信1",
"api_url": "http://192.168.1.100:5000",
"api_key": "node-api-key"
},
headers=headers
)
print(response.json())
# 发送消息
response = httpx.post(
f"{BASE_URL}/messages/send",
json={
"node_id": "wx1",
"who": "wxid_friend",
"msg": "Hello!"
},
headers=headers
)
print(response.json())
使用 curl 调用
# 添加节点
curl -X POST http://localhost:8080/api/v1/nodes \
-H "X-API-Key: your-external-api-key" \
-H "Content-Type: application/json" \
-d '{"node_id": "wx1", "name": "微信1", "api_url": "http://192.168.1.100:5000", "api_key": "key"}'
# 发送消息
curl -X POST http://localhost:8080/api/v1/messages/send \
-H "X-API-Key: your-external-api-key" \
-H "Content-Type: application/json" \
-d '{"node_id": "wx1", "who": "wxid_friend", "msg": "Hello"}'
# 获取节点状态
curl http://localhost:8080/api/v1/nodes/wx1/status \
-H "X-API-Key: your-external-api-key"
# 获取监控状态
curl http://localhost:8080/api/v1/monitor/status \
-H "X-API-Key: your-external-api-key"
# 获取最近日志
curl "http://localhost:8080/api/v1/logs/recent?count=20" \
-H "X-API-Key: your-external-api-key"
# 重置节点微信状态(回调接口)
curl -X POST http://localhost:8080/api/v1/callback/node/reset \
-H "X-API-Key: your-external-api-key" \
-H "Content-Type: application/json" \
-d '{"node_id": "wx1"}'
使用 JavaScript 调用
const API_KEY = 'your-external-api-key';
const BASE_URL = 'http://localhost:8080/api/v1';
async function sendMessage(nodeId, who, msg) {
const response = await fetch(`${BASE_URL}/messages/send`, {
method: 'POST',
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
node_id: nodeId,
who: who,
msg: msg
})
});
return await response.json();
}
// 使用示例
sendMessage('wx1', 'wxid_friend', 'Hello!')
.then(result => console.log(result));
前端开发
前端架构
前端采用纯 JavaScript 模块化设计:
static/
├── index.html # 主页面
├── css/
│ └── style.css # 样式文件
└── js/
├── api.js # API 调用封装
├── app.js # 主逻辑
└── pages/
└── templates.js # 页面模板
页面模块
系统前端包含以下页面:
| 页面 | 功能 |
|---|---|
| dashboard | 系统概览 |
| nodes | 节点管理 |
| monitor | 监控状态 |
| send | 消息发送 |
| logs | 日志查看 |
| external | 外部接口 |
| docs | 文档 |
| settings | 设置 |
API 封装 (api.js)
// 基础配置
const API_BASE = '/api/v1';
const API_KEY = 'your-api-key';
// 通用请求函数
async function apiRequest(endpoint, options = {}) {
const url = `${API_BASE}${endpoint}`;
const headers = {
'X-API-Key': API_KEY,
'Content-Type': 'application/json',
...options.headers
};
const response = await fetch(url, {
...options,
headers
});
return response.json();
}
// API 方法封装
const API = {
// 节点管理
getNodes: (group) => apiRequest(`/nodes${group ? `?group=${group}` : ''}`),
addNode: (data) => apiRequest('/nodes', { method: 'POST', body: JSON.stringify(data) }),
deleteNode: (name) => apiRequest(`/nodes/${name}`, { method: 'DELETE' }),
// 消息发送
sendMessage: (data) => apiRequest('/messages/send', { method: 'POST', body: JSON.stringify(data) }),
sendGroupMessage: (data) => apiRequest('/messages/send_group', { method: 'POST', body: JSON.stringify(data) }),
batchSendMessage: (data) => apiRequest('/messages/batch', { method: 'POST', body: JSON.stringify(data) }),
// 监控状态
getMonitorStatus: () => apiRequest('/monitor/status'),
getRecentLogs: (count) => apiRequest(`/logs/recent?count=${count || 50}`)
};
SSE 日志订阅
async function subscribeLogs(callback) {
const eventSource = new EventSource('/api/v1/logs/stream');
eventSource.onmessage = (event) => {
const logEntry = JSON.parse(event.data);
callback(logEntry);
};
eventSource.onerror = (error) => {
console.error('SSE Error:', error);
eventSource.close();
};
return eventSource; // 使用完毕后调用 close()
}
// 使用示例
const es = subscribeLogs((log) => {
console.log(`[${log.level}] ${log.message}`);
});
// 关闭时: es.close();
测试
运行测试
# 安装测试依赖
pip install pytest pytest-asyncio httpx
# 运行所有测试
pytest
# 运行指定测试文件
pytest tests/test_nodes.py
# 带详细输出
pytest -v
编写测试
# tests/test_nodes.py
import pytest
from httpx import AsyncClient
from main import app
@pytest.mark.asyncio
async def test_add_node():
async with AsyncClient(app=app, base_url="http://test") as client:
response = await client.post(
"/api/v1/nodes",
json={
"name": "test_node",
"api_url": "http://localhost:5000",
"api_key": "test_key"
},
headers={"X-API-Key": "test-key"}
)
assert response.status_code == 200
data = response.json()
assert data["success"] is True
调试技巧
启用调试模式
# 方式1:环境变量
export DEBUG=true
python main.py
# 方式2:命令行参数(如果支持)
uvicorn main:app --reload --log-level debug
# 方式3:修改 .env
DEBUG=true
查看详细日志
系统内置日志服务,可通过 API 查看:
# 获取最近日志
curl http://localhost:8080/api/v1/logs/recent?count=100 \
-H "X-API-Key: your-api-key"
# 订阅实时日志流
curl -N http://localhost:8080/api/v1/logs/stream \
-H "X-API-Key: your-api-key"
API 测试工具
- FastAPI 内置 docs:http://localhost:8080/docs
- ReDoc:http://localhost:8080/redoc
- Postman / Insomnia
代码规范
Python 代码规范
遵循 PEP 8 和项目规则:
- 使用 4 空格缩进
- 类名使用 PascalCase
- 函数/变量使用 camelCase
- 常量使用 UPPER_SNAKE_CASE
- 每个文件包含头部注释
注释要求
# ///
# filename.py
# 描述:该文件负责 [核心功能]
# 作者:AI Generated
# 创建日期:YYYY-MM-DD
# ///
def function_name(param1, param2):
"""
函数简要描述
@param {type} param1 - 参数说明
@return {type} 返回值说明
@throws {异常类型} 异常情况说明
"""
pass
部署注意事项
生产环境配置
- 修改
secret_key为强密码 - 设置
debug: false - 配置正确的
cors_origins - 使用 HTTPS
- 配置防火墙规则
使用 Nginx 反向代理
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /api {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_cache_bypass $http_upgrade;
}
}
使用 systemd 服务
# /etc/systemd/system/wxauto-center.service
[Unit]
Description=WXAuto Center Service
After=network.target
[Service]
Type=simple
User=your-user
WorkingDirectory=/path/to/wxauto_center
ExecStart=/path/to/venv/bin/python main.py
Restart=always
[Install]
WantedBy=multi-user.target
sudo systemctl enable wxauto-center
sudo systemctl start wxauto-center
关键实现细节
1. 健康检测机制 (is_node_healthy)
每次发送消息前,系统会调用此方法检测节点健康状态:
async def is_node_healthy(self, name: str) -> tuple[bool, str]:
# 1. 检查 API 状态
api_status = await self.check_node_status(name)
if api_status != NodeStatus.ACTIVE:
return False, f"API status: {api_status}"
# 2. 调用 /api/wechat/initialize 检测微信
init_result = await self.call_node_api(name, "/api/wechat/initialize", method="POST")
# 3. 解析返回状态
if not init_result.get("success"):
return False, f"WeChat check failed: {init_result.get('error')}"
# 4. 检查 code 和 status
wx_code = init_result.get("code") or init_result.get("data", {}).get("code")
wx_status = init_result.get("data", {}).get("data", {}).get("status")
if wx_code != 0:
return False, "WeChat error: ..."
if wx_status not in ["connected", "online"]:
return False, f"WeChat status: {wx_status}"
return True, "OK"
2. 消息发送流程
async def send_message(self, name: str, who: str, msg: str, msg_type: str = "text"):
# 1. 先初始化微信
await self.call_node_api(name, "/api/wechat/initialize", method="POST")
# 2. 发送消息
return await self.call_node_api(
name,
"/api/message/send",
method="POST",
data={"receiver": who, "message": msg}
)
3. 监控告警流程
async def _check_node(self, node_id: str):
# 检测 API 状态变化
api_status = await node_manager.check_node_status(node_id)
if old_api_status != api_status:
event = "node_online" if api_status == "active" else "node_offline"
await self._send_webhook(event, {...})
# 检测微信状态变化(通过发送消息检测)
wechat_status = node.wechat_status # 从节点对象获取
if old_wechat_status != wechat_status:
event = "wechat_online" if wechat_status == "online" else "wechat_offline"
await self._send_webhook(event, {...})
注意:微信状态现在通过消息发送结果自动更新,不需要主动检测。