初始化提交
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,317 @@
|
||||
# WxAuto HTTP API 使用文档
|
||||
|
||||
## 接口认证
|
||||
|
||||
所有API请求都需要在请求头中包含API密钥:
|
||||
```http
|
||||
X-API-Key: test-key-2
|
||||
```
|
||||
|
||||
## API接口示例
|
||||
|
||||
### 1. API密钥验证
|
||||
|
||||
验证API密钥是否有效。
|
||||
|
||||
```bash
|
||||
curl -X POST http://10.255.0.90:5000/api/auth/verify \
|
||||
-H "X-API-Key: test-key-2"
|
||||
```
|
||||
|
||||
响应示例:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "验证成功",
|
||||
"data": {
|
||||
"valid": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 微信基础功能
|
||||
|
||||
#### 2.1 初始化微信
|
||||
|
||||
初始化微信实例,建议在使用其他接口前先调用此接口。
|
||||
|
||||
```bash
|
||||
curl -X POST http://10.255.0.90:5000/api/wechat/initialize \
|
||||
-H "X-API-Key: test-key-2"
|
||||
```
|
||||
|
||||
响应示例:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "初始化成功",
|
||||
"data": {
|
||||
"status": "connected"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2 获取微信状态
|
||||
|
||||
检查微信连接状态。
|
||||
|
||||
```bash
|
||||
curl -X GET http://10.255.0.90:5000/api/wechat/status \
|
||||
-H "X-API-Key: test-key-2"
|
||||
```
|
||||
|
||||
响应示例:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "获取成功",
|
||||
"data": {
|
||||
"status": "online"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 消息相关接口
|
||||
|
||||
#### 3.1 发送普通文本消息
|
||||
|
||||
发送普通文本消息到指定联系人或群组。
|
||||
|
||||
```bash
|
||||
curl -X POST http://10.255.0.90:5000/api/message/send \
|
||||
-H "X-API-Key: test-key-2" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"receiver": "文件传输助手",
|
||||
"message": "这是一条测试消息",
|
||||
"at_list": ["张三", "李四"],
|
||||
"clear": true
|
||||
}'
|
||||
```
|
||||
|
||||
参数说明:
|
||||
- receiver: 接收者(联系人或群组名称)
|
||||
- message: 消息内容
|
||||
- at_list: (可选)需要@的群成员列表
|
||||
- clear: (可选)是否清除输入框,默认为true
|
||||
|
||||
响应示例:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "发送成功",
|
||||
"data": {
|
||||
"message_id": "success"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.2 发送打字机模式消息
|
||||
|
||||
使用打字机模式发送消息(模拟真人打字效果)。
|
||||
|
||||
```bash
|
||||
curl -X POST http://10.255.0.90:5000/api/message/send-typing \
|
||||
-H "X-API-Key: test-key-2" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"receiver": "文件传输助手",
|
||||
"message": "这是一条打字机模式消息\n这是第二行",
|
||||
"at_list": ["张三"],
|
||||
"clear": true
|
||||
}'
|
||||
```
|
||||
|
||||
参数说明同普通消息发送。
|
||||
|
||||
#### 3.3 发送文件
|
||||
|
||||
发送一个或多个文件。
|
||||
|
||||
```bash
|
||||
curl -X POST http://10.255.0.90:5000/api/message/send-file \
|
||||
-H "X-API-Key: test-key-2" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"receiver": "文件传输助手",
|
||||
"file_paths": [
|
||||
"D:/test/file1.txt",
|
||||
"D:/test/image.jpg"
|
||||
]
|
||||
}'
|
||||
```
|
||||
|
||||
参数说明:
|
||||
- receiver: 接收者
|
||||
- file_paths: 要发送的文件路径列表
|
||||
|
||||
响应示例:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "发送成功",
|
||||
"data": {
|
||||
"success_count": 2,
|
||||
"failed_files": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 群组相关接口
|
||||
|
||||
#### 4.1 获取群列表
|
||||
|
||||
获取当前账号的群聊列表。
|
||||
|
||||
```bash
|
||||
curl -X GET http://10.255.0.90:5000/api/group/list \
|
||||
-H "X-API-Key: test-key-2"
|
||||
```
|
||||
|
||||
响应示例:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "获取成功",
|
||||
"data": {
|
||||
"groups": [
|
||||
{"name": "测试群1"},
|
||||
{"name": "测试群2"}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.2 群组管理
|
||||
|
||||
执行群组管理操作(如重命名、退群等)。
|
||||
|
||||
```bash
|
||||
curl -X POST http://10.255.0.90:5000/api/group/manage \
|
||||
-H "X-API-Key: test-key-2" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"group_name": "测试群",
|
||||
"action": "rename",
|
||||
"params": {
|
||||
"new_name": "新群名称"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
支持的操作类型:
|
||||
- rename: 重命名群组
|
||||
- quit: 退出群组
|
||||
|
||||
### 5. 联系人相关接口
|
||||
|
||||
#### 5.1 获取好友列表
|
||||
|
||||
获取当前账号的好友列表。
|
||||
|
||||
```bash
|
||||
curl -X GET http://10.255.0.90:5000/api/contact/list \
|
||||
-H "X-API-Key: test-key-2"
|
||||
```
|
||||
|
||||
响应示例:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "获取成功",
|
||||
"data": {
|
||||
"friends": [
|
||||
{"nickname": "张三"},
|
||||
{"nickname": "李四"}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6. 健康检查接口
|
||||
|
||||
获取服务和微信连接状态。
|
||||
|
||||
```bash
|
||||
curl -X GET http://10.255.0.90:5000/api/health \
|
||||
-H "X-API-Key: test-key-2"
|
||||
```
|
||||
|
||||
响应示例:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "服务正常",
|
||||
"data": {
|
||||
"status": "ok",
|
||||
"wechat_status": "connected",
|
||||
"uptime": 3600
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 错误码说明
|
||||
|
||||
- 0: 成功
|
||||
- 1001: 认证失败(API密钥无效)
|
||||
- 1002: 参数错误
|
||||
- 2001: 微信未初始化
|
||||
- 2002: 微信已掉线
|
||||
- 3001: 发送消息失败
|
||||
- 3002: 获取消息失败
|
||||
- 4001: 群操作失败
|
||||
- 5001: 好友操作失败
|
||||
- 5000: 服务器内部错误
|
||||
|
||||
## 使用建议
|
||||
|
||||
1. 在使用其他接口前,先调用初始化接口
|
||||
2. 使用健康检查接口监控服务状态
|
||||
3. 合理处理错误码,做好重试机制
|
||||
4. 注意文件发送时的路径正确性
|
||||
5. 群发消息时建议加入适当延时
|
||||
|
||||
## PowerShell示例
|
||||
|
||||
如果您使用PowerShell,可以使用以下格式发送请求:
|
||||
|
||||
```powershell
|
||||
$headers = @{
|
||||
"X-API-Key" = "test-key-2"
|
||||
"Content-Type" = "application/json"
|
||||
}
|
||||
|
||||
$body = @{
|
||||
receiver = "文件传输助手"
|
||||
message = "测试消息"
|
||||
} | ConvertTo-Json
|
||||
|
||||
Invoke-RestMethod -Method Post -Uri "http://10.255.0.90:5000/api/message/send" -Headers $headers -Body $body
|
||||
```
|
||||
|
||||
## Python示例
|
||||
|
||||
使用Python requests库的示例:
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
API_KEY = "test-key-2"
|
||||
BASE_URL = "http://10.255.0.90:5000/api"
|
||||
|
||||
headers = {
|
||||
"X-API-Key": API_KEY,
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
# 发送消息示例
|
||||
response = requests.post(
|
||||
f"{BASE_URL}/message/send",
|
||||
headers=headers,
|
||||
json={
|
||||
"receiver": "文件传输助手",
|
||||
"message": "测试消息"
|
||||
}
|
||||
)
|
||||
|
||||
print(response.json())
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,344 @@
|
||||
# ///
|
||||
# API.md
|
||||
# 描述:WXAuto Center API 接口文档
|
||||
# 作者:AI Generated
|
||||
# 创建日期:2026-04-06
|
||||
# 更新日期:2026-04-06
|
||||
# ///
|
||||
|
||||
# WXAuto Center API 接口文档
|
||||
|
||||
## 概述
|
||||
|
||||
本系统提供完整的 RESTful API,支持节点管理、消息发送、插件管理、外部程序接入、Webhook 管理等功能。所有 API 均使用 JSON 格式进行请求和响应。
|
||||
|
||||
## 基础信息
|
||||
|
||||
| 项目 | 说明 |
|
||||
|------|------|
|
||||
| Base URL | `http://{host}:{port}/api/v1` |
|
||||
| 默认端口 | 8080 |
|
||||
| 内部 API 认证 | Header: `X-API-Key: your-external-api-key` |
|
||||
| 外部 API 认证 | Header: `X-ExternalKey: your-external-api-key` |
|
||||
| 响应格式 | JSON |
|
||||
|
||||
## API 列表
|
||||
|
||||
### 节点管理 `/api/v1/nodes`
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | `/nodes/` | 获取所有节点 |
|
||||
| GET | `/nodes/{node_id}` | 获取指定节点信息 |
|
||||
| POST | `/nodes/` | 添加节点 |
|
||||
| PUT | `/nodes/{node_id}` | 更新节点信息 |
|
||||
| DELETE | `/nodes/{node_id}` | 删除节点 |
|
||||
| GET | `/nodes/{node_id}/status` | 检查节点状态 |
|
||||
| POST | `/nodes/{node_id}/enable` | 启用节点 |
|
||||
| POST | `/nodes/{node_id}/disable` | 禁用节点 |
|
||||
| GET | `/nodes/{node_id}/friends` | 获取节点好友列表 |
|
||||
| GET | `/nodes/{node_id}/groups` | 获取节点群列表 |
|
||||
| GET | `/nodes/{node_id}/messages/{chat_name}` | 获取聊天消息 |
|
||||
|
||||
### 消息管理 `/api/v1/messages`
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| POST | `/messages/send` | 发送消息 |
|
||||
| POST | `/messages/send_group` | 发送群消息 |
|
||||
| POST | `/messages/batch` | 批量发送消息 |
|
||||
| POST | `/messages/template/{node_id}/{who}` | 发送模板消息 |
|
||||
| GET | `/messages/history/{node_id}/{chat_name}` | 获取消息历史 |
|
||||
|
||||
### 插件管理 `/api/v1/plugins`
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | `/plugins/` | 获取所有插件 |
|
||||
| GET | `/plugins/{plugin_name}` | 获取插件详情 |
|
||||
| GET | `/plugins/{plugin_name}/schema` | 获取插件表单Schema |
|
||||
| POST | `/plugins/{plugin_name}/enable` | 启用插件 |
|
||||
| POST | `/plugins/{plugin_name}/disable` | 禁用插件 |
|
||||
| PUT | `/plugins/{plugin_name}/config` | 更新插件配置 |
|
||||
| POST | `/plugins/{plugin_name}/execute` | 执行插件 |
|
||||
| GET | `/plugins/{plugin_name}/logs` | 获取插件日志 |
|
||||
| POST | `/plugins/{plugin_name}/logs/clear` | 清空插件日志 |
|
||||
| GET | `/plugins/type/{plugin_type}` | 按类型获取插件 |
|
||||
|
||||
### 回调接口 `/api/v1/callback`
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| POST | `/callback/node/reset` | 重置节点微信状态 |
|
||||
| POST | `/callback/node/check` | 检测节点微信状态 |
|
||||
| GET | `/callback/node/{node_id}/status` | 获取节点回调状态 |
|
||||
|
||||
### Webhook 管理 `/api/v1/webhook`
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | `/webhook/` | 获取所有Webhook |
|
||||
| GET | `/webhook/{webhook_id}` | 获取指定Webhook |
|
||||
| POST | `/webhook/` | 添加Webhook |
|
||||
| PUT | `/webhook/{webhook_id}` | 更新Webhook |
|
||||
| DELETE | `/webhook/{webhook_id}` | 删除Webhook |
|
||||
| POST | `/webhook/{webhook_id}/enable` | 启用Webhook |
|
||||
| POST | `/webhook/{webhook_id}/disable` | 禁用Webhook |
|
||||
|
||||
### 外部接口 `/api/v1/external`
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| POST | `/external/send` | 外部接口-发送消息 |
|
||||
| POST | `/external/trigger` | 外部接口-触发数据处理 |
|
||||
| POST | `/external/plugin/execute` | 外部接口-执行插件 |
|
||||
| GET | `/external/plugins` | 外部接口-获取可用插件列表 |
|
||||
| GET | `/external/nodes` | 外部接口-获取可用节点 |
|
||||
| POST | `/external/ai/process` | 外部接口-AI处理消息 |
|
||||
| POST | `/external/webhook/{event}` | 外部接口-Webhook接收 |
|
||||
|
||||
---
|
||||
|
||||
## 节点管理 API 详解
|
||||
|
||||
### 获取所有节点
|
||||
|
||||
```
|
||||
GET /api/v1/nodes/
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": [
|
||||
{
|
||||
"node_id": "wx1",
|
||||
"name": "微信1",
|
||||
"api_url": "http://192.168.20.84:5000",
|
||||
"enabled": true,
|
||||
"description": "",
|
||||
"group": "wechat",
|
||||
"status": "error",
|
||||
"wechat_status": "online",
|
||||
"is_healthy": false
|
||||
}
|
||||
],
|
||||
"count": 1
|
||||
}
|
||||
```
|
||||
|
||||
### 添加节点
|
||||
|
||||
```
|
||||
POST /api/v1/nodes/
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"node_id": "wx1",
|
||||
"name": "微信1",
|
||||
"api_url": "http://192.168.20.84:5000",
|
||||
"api_key": "your-node-api-key",
|
||||
"description": "测试节点",
|
||||
"group": "wechat"
|
||||
}
|
||||
```
|
||||
|
||||
### 更新节点
|
||||
|
||||
```
|
||||
PUT /api/v1/nodes/{node_id}
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"api_url": "http://192.168.20.84:5000",
|
||||
"api_key": "updated-key"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 消息发送 API 详解
|
||||
|
||||
### 发送消息
|
||||
|
||||
```
|
||||
POST /api/v1/messages/send
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"node_id": "wx1",
|
||||
"who": "文件传输助手",
|
||||
"msg": "测试消息",
|
||||
"msg_type": "text"
|
||||
}
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "消息发送成功"
|
||||
}
|
||||
```
|
||||
|
||||
### 发送群消息
|
||||
|
||||
```
|
||||
POST /api/v1/messages/send_group
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"node_id": "wx1",
|
||||
"group_name": "测试群",
|
||||
"msg": "群消息测试",
|
||||
"msg_type": "text"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 插件管理 API 详解
|
||||
|
||||
### 获取所有插件
|
||||
|
||||
```
|
||||
GET /api/v1/plugins/
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "http_scheduled_sender",
|
||||
"version": "1.0.0",
|
||||
"type": "scheduled_task",
|
||||
"description": "定时HTTP数据源推送",
|
||||
"enabled": true,
|
||||
"config": {
|
||||
"node_id": "wx1",
|
||||
"receiver": "asq",
|
||||
"cron": "0 8 * * *"
|
||||
}
|
||||
}
|
||||
],
|
||||
"count": 1
|
||||
}
|
||||
```
|
||||
|
||||
### 配置插件
|
||||
|
||||
```
|
||||
PUT /api/v1/plugins/{plugin_name}/config
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"name": "http_scheduled_sender",
|
||||
"config": {
|
||||
"node_id": "wx1",
|
||||
"receiver": "文件传输助手",
|
||||
"cron": "0 8 * * *",
|
||||
"http_url": "https://api.example.com/news",
|
||||
"message_template": "📰 {title}\n{url}"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 执行插件
|
||||
|
||||
```
|
||||
POST /api/v1/plugins/{plugin_name}/execute
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"action": "preview"
|
||||
}
|
||||
```
|
||||
|
||||
**action 选项:**
|
||||
- `send` - 执行完整流程
|
||||
- `fetch` - 仅请求API
|
||||
- `parse` - 请求并解析数据
|
||||
- `preview` - 预览格式化后的消息
|
||||
- `test` - 测试cron表达式
|
||||
|
||||
---
|
||||
|
||||
## 通用响应格式
|
||||
|
||||
**成功:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {},
|
||||
"message": "操作成功"
|
||||
}
|
||||
```
|
||||
|
||||
**失败:**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"error": "错误描述"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 插件类型
|
||||
|
||||
| 类型 | 值 | 说明 |
|
||||
|------|-----|------|
|
||||
| `message_handler` | MESSAGE_HANDLER | 消息处理器 |
|
||||
| `data_source` | DATA_SOURCE | 数据源 |
|
||||
| `action_trigger` | ACTION_TRIGGER | 动作触发器 |
|
||||
| `ai_agent` | AI_AGENT | AI智能体 |
|
||||
| `scheduled_task` | SCHEDULED_TASK | 定时任务 |
|
||||
| `http_scheduled_sender` | HTTP_SCHEDULED_SENDER | 定时HTTP推送 |
|
||||
| `custom` | CUSTOM | 自定义 |
|
||||
|
||||
---
|
||||
|
||||
## 节点数据模型
|
||||
|
||||
```json
|
||||
{
|
||||
"node_id": "wx1",
|
||||
"name": "微信1",
|
||||
"api_url": "http://192.168.20.84:5000",
|
||||
"api_key": "your-key",
|
||||
"enabled": true,
|
||||
"description": "",
|
||||
"group": "wechat",
|
||||
"status": "active",
|
||||
"wechat_status": "online",
|
||||
"is_healthy": true
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| node_id | string | 节点唯一标识 |
|
||||
| name | string | 节点显示名称 |
|
||||
| api_url | string | 节点API地址 |
|
||||
| api_key | string | 节点API密钥 |
|
||||
| enabled | bool | 是否启用 |
|
||||
| description | string | 节点描述 |
|
||||
| group | string | 节点分组 |
|
||||
| status | string | API状态 (active/inactive/error) |
|
||||
| wechat_status | string | 微信状态 (online/offline) |
|
||||
| is_healthy | bool | 健康状态 |
|
||||
@@ -0,0 +1,235 @@
|
||||
# ///
|
||||
# ARCHITECTURE.md
|
||||
# 描述:WXAuto Center 系统架构文档
|
||||
# 作者:AI Generated
|
||||
# 创建日期:2026-04-05
|
||||
# 更新日期:2026-04-06
|
||||
# ///
|
||||
|
||||
# WXAuto Center 系统架构文档
|
||||
|
||||
## 概述
|
||||
|
||||
WXAuto Center 是一个模块化的微信多节点中控系统,采用前后端分离架构,支持多节点管理、消息发送、插件扩展、定时任务等功能。
|
||||
|
||||
## 系统架构图
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ WXAuto Center │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Frontend (Static) │ │
|
||||
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
|
||||
│ │ │Dashboard │ │ Nodes │ │ Messages │ │ Plugins │ │ │
|
||||
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ FastAPI Backend │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌───────────┐ │ │
|
||||
│ │ │nodes router │ │messages router│ │plugins router│ │webhook router│ │ │
|
||||
│ │ └─────────────┘ └─────────────┘ └─────────────┘ └───────────┘ │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌───────────┐ │ │
|
||||
│ │ │callback router│ │external router│ │webhook service│ │queue service│ │ │
|
||||
│ │ └─────────────┘ └─────────────┘ └─────────────┘ └───────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌────────────────────────────┼────────────────────────────┐ │
|
||||
│ ▼ ▼ ▼ │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ Redis │ │ PostgreSQL │ │ Nodes │ │
|
||||
│ │ (Queue) │ │ (Storage) │ │ (External) │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 核心组件
|
||||
|
||||
### 1. 前端 (Frontend)
|
||||
|
||||
静态文件服务,基于原生 JavaScript 开发。
|
||||
|
||||
**页面模块:**
|
||||
| 页面 | 文件 | 说明 |
|
||||
|------|------|------|
|
||||
| 首页/仪表盘 | app.js | 系统概览 |
|
||||
| 节点管理 | app.js | 节点 CRUD |
|
||||
| 快捷消息 | app.js | 快速发送消息 |
|
||||
| 监控告警 | app.js | Webhook 配置 |
|
||||
| 日志查看 | app.js | 系统日志 |
|
||||
| 外部接入 | app.js | 外部 API 文档 |
|
||||
| 插件管理 | app.js | 插件配置 |
|
||||
|
||||
### 2. 后端 (Backend)
|
||||
|
||||
基于 FastAPI 的 RESTful API 服务。
|
||||
|
||||
**API 模块:**
|
||||
| 模块 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| nodes | /api/v1/nodes | 节点管理 |
|
||||
| messages | /api/v1/messages | 消息发送 |
|
||||
| plugins | /api/v1/plugins | 插件管理 |
|
||||
| webhook | /api/v1/webhook | Webhook 管理 |
|
||||
| callback | /api/v1/callback | 回调接口 |
|
||||
| external | /api/v1/external | 外部接口 |
|
||||
|
||||
### 3. 服务层 (Services)
|
||||
|
||||
| 服务 | 说明 |
|
||||
|------|------|
|
||||
| node_manager | 节点管理器,内存缓存 |
|
||||
| monitor_service | 节点健康监控服务 |
|
||||
| scheduler_service | 定时任务调度服务 |
|
||||
| log_service | 日志服务 |
|
||||
| queue_service | 消息队列服务 |
|
||||
| webhook_service | Webhook 通知服务 |
|
||||
|
||||
### 4. 插件系统 (Plugins)
|
||||
|
||||
| 插件 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| http_data_source | DATA_SOURCE | HTTP 数据源 |
|
||||
| database_query | DATA_SOURCE | 数据库查询 |
|
||||
| webhook_trigger | ACTION_TRIGGER | Webhook 触发 |
|
||||
| simple_ai_agent | AI_AGENT | AI 智能体 |
|
||||
| http_scheduled_sender | SCHEDULED_TASK | 定时 HTTP 推送 |
|
||||
|
||||
### 5. 数据层 (Data)
|
||||
|
||||
| 组件 | 说明 |
|
||||
|------|------|
|
||||
| PostgreSQL | 主数据库,存储节点、Webhook、日志、插件配置 |
|
||||
| Redis | 消息队列、缓存 |
|
||||
|
||||
---
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
wxauto_api/
|
||||
├── main.py # 应用入口
|
||||
├── config.py # 配置管理
|
||||
├── models.py # 数据模型
|
||||
├── database_service.py # 数据库服务
|
||||
├── requirements.txt # Python 依赖
|
||||
├── Dockerfile # Docker 镜像
|
||||
├── docker-compose.yml # Docker 编排
|
||||
│
|
||||
├── api/ # API 路由
|
||||
│ ├── __init__.py
|
||||
│ ├── nodes.py # 节点管理
|
||||
│ ├── messages.py # 消息发送
|
||||
│ ├── plugins.py # 插件管理
|
||||
│ ├── webhook.py # Webhook 管理
|
||||
│ ├── callback.py # 回调接口
|
||||
│ └── external.py # 外部接口
|
||||
│
|
||||
├── services/ # 业务服务
|
||||
│ ├── __init__.py
|
||||
│ ├── node_manager.py # 节点管理
|
||||
│ ├── monitor_service.py # 健康监控
|
||||
│ ├── scheduler_service.py # 定时调度
|
||||
│ ├── log_service.py # 日志服务
|
||||
│ ├── queue_service.py # 队列服务
|
||||
│ └── webhook_service.py # Webhook 服务
|
||||
│
|
||||
├── plugins/ # 插件系统
|
||||
│ ├── __init__.py
|
||||
│ ├── base.py # 插件基类
|
||||
│ ├── builtin.py # 内置插件
|
||||
│ └── http_scheduled_sender.py # 定时推送插件
|
||||
│
|
||||
├── utils/ # 工具函数
|
||||
│ └── auth.py # 认证中间件
|
||||
│
|
||||
├── static/ # 静态文件
|
||||
│ ├── index.html # 主页面
|
||||
│ └── js/ # JavaScript
|
||||
│ ├── api.js # API 封装
|
||||
│ ├── app.js # 主应用
|
||||
│ └── pages/
|
||||
│ └── templates.js # 页面模板
|
||||
│
|
||||
└── doc/ # 文档
|
||||
└── wxauto_center/
|
||||
├── ARCHITECTURE.md # 架构文档
|
||||
├── API.md # API 文档
|
||||
├── DATABASE.md # 数据库文档
|
||||
├── FLOWS.md # 流程文档
|
||||
└── PLUGIN.md # 插件文档
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 技术栈
|
||||
|
||||
| 层级 | 技术 | 说明 |
|
||||
|------|------|------|
|
||||
| 前端 | HTML/CSS/JavaScript | 原生开发,无框架依赖 |
|
||||
| 后端 | Python 3.11 + FastAPI | 高性能异步框架 |
|
||||
| 数据库 | PostgreSQL | 关系型数据库 |
|
||||
| 缓存/队列 | Redis | 内存数据库、消息队列 |
|
||||
| 容器 | Docker + Docker Compose | 容器化部署 |
|
||||
| ORM | SQLAlchemy | Python ORM |
|
||||
| HTTP 客户端 | httpx | 异步 HTTP 客户端 |
|
||||
|
||||
---
|
||||
|
||||
## 部署架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Docker Network │
|
||||
│ │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ wxauto-center│ │ wxauto-redis │ │wxauto-postgres│ │
|
||||
│ │ :8080 │ │ :6379 │ │ :5432 │ │
|
||||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
┌──────────────────┐ ┌──────────────────┐
|
||||
│ External Nodes │ │ External │
|
||||
│ (wxauto nodes) │ │ Webhook URLs │
|
||||
│ :5000 │ │ │
|
||||
└──────────────────┘ └──────────────────┘
|
||||
```
|
||||
|
||||
### 环境变量
|
||||
|
||||
| 变量 | 说明 | 默认值 |
|
||||
|------|------|--------|
|
||||
| `POSTGRES_USER` | PostgreSQL 用户 | wxauto |
|
||||
| `POSTGRES_PASSWORD` | PostgreSQL 密码 | wxauto_password |
|
||||
| `POSTGRES_DB` | 数据库名 | wxauto |
|
||||
| `REDIS_PASSWORD` | Redis 密码 | wxauto_redis |
|
||||
| `API_KEY` | API 认证密钥 | your-external-api-key |
|
||||
| `EXTERNAL_KEY` | 外部接口密钥 | your-external-api-key |
|
||||
|
||||
---
|
||||
|
||||
## 安全机制
|
||||
|
||||
### 1. API 认证
|
||||
- 内部 API:Header `X-API-Key`
|
||||
- 外部 API:Header `X-ExternalKey`
|
||||
|
||||
### 2. 异常处理
|
||||
- 全局异常处理器
|
||||
- 所有 API 调用包裹 try/except
|
||||
- 10 秒 HTTP 超时
|
||||
|
||||
### 3. 数据一致性
|
||||
- 数据库优先原则
|
||||
- 启动时从数据库加载配置
|
||||
- 操作时同时更新内存和数据库
|
||||
@@ -0,0 +1,618 @@
|
||||
# ///
|
||||
# CONFIG.md
|
||||
# 描述:配置文件说明
|
||||
# 作者:AI Generated
|
||||
# 创建日期:2026-04-06
|
||||
# 最后更新:2026-04-06
|
||||
# ///
|
||||
|
||||
# WXAuto Center 配置文件说明
|
||||
|
||||
## 概述
|
||||
|
||||
系统配置支持多种配置源,按优先级从高到低依次为:
|
||||
1. 环境变量(`.env` 文件)
|
||||
2. 配置文件(`config.json`)
|
||||
3. 代码默认值
|
||||
|
||||
## 配置文件结构
|
||||
|
||||
### config.json
|
||||
|
||||
主配置文件,仅包含应用配置。**节点配置和 Webhook 配置已迁移到数据库**。
|
||||
|
||||
```json
|
||||
{
|
||||
"app_name": "WXAuto Center",
|
||||
"host": "0.0.0.0",
|
||||
"port": 8080,
|
||||
"debug": true,
|
||||
"secret_key": "wxauto-center-secret-key-change-in-production",
|
||||
"workers": 1,
|
||||
"cors_origins": ["*"],
|
||||
"api_prefix": "/api/v1",
|
||||
"external_api_key": "your-external-api-key",
|
||||
"monitor": {
|
||||
"enabled": true,
|
||||
"check_interval": 30
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### .env 环境变量文件
|
||||
|
||||
Docker 环境变量配置文件。
|
||||
|
||||
```
|
||||
# ///
|
||||
# .env
|
||||
# 描述:环境变量配置(用于 Docker 环境)
|
||||
# ///
|
||||
|
||||
# 数据库配置
|
||||
DATABASE_URL=postgresql://wxauto:wxauto_password@postgres:5432/wxauto
|
||||
|
||||
# Redis 配置
|
||||
REDIS_URL=redis://redis:6379/0
|
||||
|
||||
# 应用配置
|
||||
APP_NAME=WXAuto Center
|
||||
HOST=0.0.0.0
|
||||
PORT=8080
|
||||
DEBUG=true
|
||||
SECRET_KEY=wxauto-center-secret-key-change-in-production
|
||||
WORKERS=1
|
||||
|
||||
# API 配置
|
||||
API_PREFIX=/api/v1
|
||||
EXTERNAL_API_KEY=your-external-api-key
|
||||
CORS_ORIGINS=["*"]
|
||||
|
||||
# 监控配置
|
||||
MONITOR_ENABLED=true
|
||||
MONITOR_CHECK_INTERVAL=30
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 配置项详细说明
|
||||
|
||||
### 应用配置
|
||||
|
||||
#### app_name
|
||||
|
||||
| 属性 | 说明 |
|
||||
|------|------|
|
||||
| 类型 | string |
|
||||
| 默认值 | "WXAuto Center" |
|
||||
| 环境变量 | APP_NAME |
|
||||
| 说明 | 应用名称,显示在页面标题和日志中 |
|
||||
|
||||
#### host
|
||||
|
||||
| 属性 | 说明 |
|
||||
|------|------|
|
||||
| 类型 | string |
|
||||
| 默认值 | "0.0.0.0" |
|
||||
| 环境变量 | HOST |
|
||||
| 说明 | 服务监听地址,0.0.0.0 表示监听所有网络接口 |
|
||||
|
||||
#### port
|
||||
|
||||
| 属性 | 说明 |
|
||||
|------|------|
|
||||
| 类型 | int |
|
||||
| 默认值 | 8080 |
|
||||
| 环境变量 | PORT |
|
||||
| 说明 | 服务监听端口 |
|
||||
|
||||
#### debug
|
||||
|
||||
| 属性 | 说明 |
|
||||
|------|------|
|
||||
| 类型 | bool |
|
||||
| 默认值 | false |
|
||||
| 环境变量 | DEBUG |
|
||||
| 说明 | 调试模式,启用时支持热重载 |
|
||||
|
||||
#### secret_key
|
||||
|
||||
| 属性 | 说明 |
|
||||
|------|------|
|
||||
| 类型 | string |
|
||||
| 默认值 | "wxauto-center-secret-key-change-in-production" |
|
||||
| 环境变量 | SECRET_KEY |
|
||||
| 说明 | 应用密钥,用于会话加密等安全用途,生产环境必须修改 |
|
||||
|
||||
---
|
||||
|
||||
### API 配置
|
||||
|
||||
#### api_prefix
|
||||
|
||||
| 属性 | 说明 |
|
||||
|------|------|
|
||||
| 类型 | string |
|
||||
| 默认值 | "/api/v1" |
|
||||
| 环境变量 | API_PREFIX |
|
||||
| 说明 | API 路由前缀,所有 API 路径都会此前缀开头 |
|
||||
|
||||
#### external_api_key
|
||||
|
||||
| 属性 | 说明 |
|
||||
|------|------|
|
||||
| 类型 | string |
|
||||
| 默认值 | "your-external-api-key" |
|
||||
| 环境变量 | EXTERNAL_API_KEY |
|
||||
| 说明 | 外部 API 密钥,用于外部系统调用时的认证 |
|
||||
|
||||
#### cors_origins
|
||||
|
||||
| 属性 | 说明 |
|
||||
|------|------|
|
||||
| 类型 | array[string] |
|
||||
| 默认值 | ["*"] |
|
||||
| 环境变量 | CORS_ORIGINS |
|
||||
| 说明 | 允许的 CORS 来源,* 表示允许所有来源(仅限开发环境使用) |
|
||||
|
||||
---
|
||||
|
||||
## 节点配置 (NodeConfig)
|
||||
|
||||
**重要更新**:节点配置已从 config.json 迁移到 PostgreSQL 数据库的 `nodes` 表。
|
||||
|
||||
### 配置存储
|
||||
|
||||
| 存储位置 | 说明 |
|
||||
|----------|------|
|
||||
| PostgreSQL | nodes 表(生产环境推荐) |
|
||||
| config.json | 已废弃,不再支持 |
|
||||
|
||||
### 节点数据模型
|
||||
|
||||
```json
|
||||
{
|
||||
"node_id": "wx1",
|
||||
"name": "微信1",
|
||||
"api_url": "http://192.168.1.100:5000",
|
||||
"api_key": "your-node-api-key",
|
||||
"enabled": true,
|
||||
"description": "主节点",
|
||||
"group": "default",
|
||||
"status": "active",
|
||||
"wechat_status": "online",
|
||||
"is_healthy": true
|
||||
}
|
||||
```
|
||||
|
||||
### 节点标识说明
|
||||
|
||||
每个节点有两个标识:
|
||||
|
||||
| 字段 | 说明 | 示例 |
|
||||
|------|------|------|
|
||||
| node_id | 节点唯一标识,用于 API 调用 | "wx1", "node_001" |
|
||||
| name | 节点显示名称,用于界面展示 | "微信1", "测试节点" |
|
||||
|
||||
### 配置项说明
|
||||
|
||||
| 配置项 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|--------|------|------|--------|------|
|
||||
| node_id | string | 是 | - | 节点唯一标识(不可重复) |
|
||||
| name | string | 否 | 等于 node_id | 节点显示名称 |
|
||||
| api_url | string | 是 | - | 节点 API 服务地址 |
|
||||
| api_key | string | 是 | - | 节点 API 密钥 |
|
||||
| enabled | bool | 否 | true | 是否启用该节点 |
|
||||
| description | string | 否 | "" | 节点描述信息 |
|
||||
| group | string | 否 | "default" | 节点分组,用于分类管理 |
|
||||
|
||||
### API 管理节点
|
||||
|
||||
通过 API 管理节点配置:
|
||||
|
||||
```bash
|
||||
# 添加节点
|
||||
curl -X POST http://localhost:8080/api/v1/nodes \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-API-Key: your-external-api-key" \
|
||||
-d '{
|
||||
"node_id": "wx1",
|
||||
"name": "微信1",
|
||||
"api_url": "http://192.168.1.100:5000",
|
||||
"api_key": "your-node-api-key",
|
||||
"description": "主节点",
|
||||
"group": "production"
|
||||
}'
|
||||
|
||||
# 获取所有节点
|
||||
curl http://localhost:8080/api/v1/nodes \
|
||||
-H "X-API-Key: your-external-api-key"
|
||||
|
||||
# 更新节点
|
||||
curl -X PUT http://localhost:8080/api/v1/nodes/wx1 \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-API-Key: your-external-api-key" \
|
||||
-d '{"enabled": false}'
|
||||
|
||||
# 删除节点
|
||||
curl -X DELETE http://localhost:8080/api/v1/nodes/wx1 \
|
||||
-H "X-API-Key: your-external-api-key"
|
||||
```
|
||||
|
||||
### 节点分组
|
||||
|
||||
节点分组功能允许将节点按业务线或用途进行分类管理:
|
||||
|
||||
```bash
|
||||
# 查询特定分组的节点
|
||||
curl "http://localhost:8080/api/v1/nodes?group=production" \
|
||||
-H "X-API-Key: your-external-api-key"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Webhook 配置 (WebhookConfig)
|
||||
|
||||
**重要更新**:Webhook 配置已从 config.json 迁移到 PostgreSQL 数据库的 `webhook_urls` 表。
|
||||
|
||||
### 配置存储
|
||||
|
||||
| 存储位置 | 说明 |
|
||||
|----------|------|
|
||||
| PostgreSQL | webhook_urls 表(推荐) |
|
||||
| config.json | 已废弃,不再支持 |
|
||||
|
||||
### Webhook 数据模型
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"name": "企业微信告警",
|
||||
"url": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxx",
|
||||
"format": "wechat",
|
||||
"enabled": true,
|
||||
"event_types": "wechat_offline,wechat_online,node_offline,node_online",
|
||||
"created_at": "2026-04-06T10:00:00",
|
||||
"updated_at": "2026-04-06T10:00:00"
|
||||
}
|
||||
```
|
||||
|
||||
### 配置项说明
|
||||
|
||||
| 配置项 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|--------|------|------|--------|------|
|
||||
| name | string | 是 | - | Webhook 名称 |
|
||||
| url | string | 是 | - | Webhook URL 地址 |
|
||||
| format | string | 否 | "bark" | 消息格式:bark 或 wechat |
|
||||
| enabled | bool | 否 | true | 是否启用 |
|
||||
| event_types | string | 否 | 全部事件 | 需要触发 Webhook 的事件类型 |
|
||||
|
||||
### 支持的事件类型
|
||||
|
||||
| 事件类型 | 说明 | 触发时机 |
|
||||
|----------|------|----------|
|
||||
| api_error | API 错误 | 调用节点 API 失败 |
|
||||
| wechat_offline | 微信掉线 | 微信状态变为 offline |
|
||||
| wechat_online | 微信上线 | 微信状态变为 online/connected |
|
||||
| node_offline | 节点离线 | 节点 API 不可达 |
|
||||
| node_online | 节点在线 | 节点 API 恢复可用 |
|
||||
|
||||
### 消息格式
|
||||
|
||||
#### 企业微信格式 (format: "wechat")
|
||||
|
||||
```json
|
||||
{
|
||||
"msgtype": "text",
|
||||
"text": {
|
||||
"content": "【WXAuto Center 告警】\n事件类型: 微信掉线\n节点: wx1\n状态: offline\n时间: 2026-04-05 10:00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Bark 格式 (format: "bark")
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "WXAuto告警 - 微信掉线",
|
||||
"body": "wx1\n状态: offline\n时间: 2026-04-05 10:00:00"
|
||||
}
|
||||
```
|
||||
|
||||
### API 管理 Webhook
|
||||
|
||||
```bash
|
||||
# 添加 Webhook
|
||||
curl -X POST http://localhost:8080/api/v1/webhook \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-API-Key: your-external-api-key" \
|
||||
-d '{
|
||||
"name": "企业微信告警",
|
||||
"url": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxx",
|
||||
"format": "wechat",
|
||||
"enabled": true,
|
||||
"event_types": "wechat_offline,wechat_online,node_offline,node_online"
|
||||
}'
|
||||
|
||||
# 获取所有 Webhook
|
||||
curl http://localhost:8080/api/v1/webhook \
|
||||
-H "X-API-Key: your-external-api-key"
|
||||
|
||||
# 更新 Webhook
|
||||
curl -X PUT http://localhost:8080/api/v1/webhook/1 \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-API-Key: your-external-api-key" \
|
||||
-d '{"enabled": false}'
|
||||
|
||||
# 删除 Webhook
|
||||
curl -X DELETE http://localhost:8080/api/v1/webhook/1 \
|
||||
-H "X-API-Key: your-external-api-key"
|
||||
|
||||
# 启用/禁用 Webhook
|
||||
curl -X POST http://localhost:8080/api/v1/webhook/1/enable \
|
||||
-H "X-API-Key: your-external-api-key"
|
||||
|
||||
curl -X POST http://localhost:8080/api/v1/webhook/1/disable \
|
||||
-H "X-API-Key: your-external-api-key"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 监控配置 (MonitorConfig)
|
||||
|
||||
监控服务负责定时检测节点和微信状态。
|
||||
|
||||
```json
|
||||
{
|
||||
"monitor": {
|
||||
"enabled": true,
|
||||
"check_interval": 30
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 配置项说明
|
||||
|
||||
| 配置项 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|--------|------|------|--------|------|
|
||||
| enabled | bool | 否 | true | 是否启用监控服务 |
|
||||
| check_interval | int | 否 | 30 | 检测间隔(秒) |
|
||||
|
||||
### 检测逻辑
|
||||
|
||||
1. **API 检测**:定期调用节点 `/health` 接口检查节点是否在线
|
||||
2. **微信检测**:定期调用 `/api/wechat/initialize` 检测微信连接状态
|
||||
3. **状态变化**:当检测到状态变化时,触发 Webhook 通知
|
||||
|
||||
---
|
||||
|
||||
## 数据库配置
|
||||
|
||||
数据库配置通过环境变量设置:
|
||||
|
||||
| 环境变量 | 说明 | 默认值 |
|
||||
|----------|------|--------|
|
||||
| DATABASE_URL | PostgreSQL 连接 URL | postgresql://wxauto:wxauto_password@postgres:5432/wxauto |
|
||||
|
||||
### Docker 环境
|
||||
|
||||
```bash
|
||||
DATABASE_URL=postgresql://wxauto:wxauto_password@postgres:5432/wxauto
|
||||
```
|
||||
|
||||
### 本地环境
|
||||
|
||||
```bash
|
||||
DATABASE_URL=postgresql://wxauto:wxauto_password@localhost:5432/wxauto
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Redis 配置
|
||||
|
||||
Redis 用于消息队列和缓存支持。
|
||||
|
||||
| 环境变量 | 说明 | 默认值 |
|
||||
|----------|------|--------|
|
||||
| REDIS_URL | Redis 连接 URL | redis://redis:6379/0 |
|
||||
|
||||
### Docker 环境
|
||||
|
||||
```bash
|
||||
REDIS_URL=redis://redis:6379/0
|
||||
```
|
||||
|
||||
### 本地环境
|
||||
|
||||
```bash
|
||||
REDIS_URL=redis://localhost:6379/0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Workers 配置
|
||||
|
||||
Workers 用于多进程部署,提高并发处理能力。
|
||||
|
||||
```json
|
||||
{
|
||||
"workers": 1
|
||||
}
|
||||
```
|
||||
|
||||
### 配置项说明
|
||||
|
||||
| 配置项 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|--------|------|------|--------|------|
|
||||
| workers | int | 否 | 1 | 工作进程数,1 表示单进程模式 |
|
||||
|
||||
### 启动方式
|
||||
|
||||
| 模式 | workers | 说明 |
|
||||
|------|---------|------|
|
||||
| 单进程 | 1 | 默认模式,不启用多进程 |
|
||||
| 多进程 | >1 | 启用多进程模式,需要 Redis 支持 |
|
||||
|
||||
**注意**:多进程模式需要 Redis 支持,队列服务依赖 Redis 进行进程间通信。
|
||||
|
||||
### 启动命令
|
||||
|
||||
```bash
|
||||
# 单进程
|
||||
python main.py
|
||||
|
||||
# 多进程
|
||||
python main.py --workers 4
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 完整配置示例
|
||||
|
||||
### config.json
|
||||
|
||||
```json
|
||||
{
|
||||
"app_name": "WXAuto Center",
|
||||
"host": "0.0.0.0",
|
||||
"port": 8080,
|
||||
"debug": false,
|
||||
"secret_key": "your-production-secret-key",
|
||||
"api_prefix": "/api/v1",
|
||||
"external_api_key": "your-external-api-key",
|
||||
"cors_origins": ["http://localhost:3000"],
|
||||
"workers": 1,
|
||||
"monitor": {
|
||||
"enabled": true,
|
||||
"check_interval": 30
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### .env
|
||||
|
||||
```bash
|
||||
# 数据库配置
|
||||
DATABASE_URL=postgresql://wxauto:wxauto_password@postgres:5432/wxauto
|
||||
|
||||
# Redis 配置
|
||||
REDIS_URL=redis://redis:6379/0
|
||||
|
||||
# 应用配置
|
||||
APP_NAME=WXAuto Center
|
||||
HOST=0.0.0.0
|
||||
PORT=8080
|
||||
DEBUG=false
|
||||
SECRET_KEY=your-production-secret-key
|
||||
WORKERS=1
|
||||
|
||||
# API 配置
|
||||
API_PREFIX=/api/v1
|
||||
EXTERNAL_API_KEY=your-external-api-key
|
||||
CORS_ORIGINS=["http://localhost:3000"]
|
||||
|
||||
# 监控配置
|
||||
MONITOR_ENABLED=true
|
||||
MONITOR_CHECK_INTERVAL=30
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 环境变量配置优先级
|
||||
|
||||
某些敏感配置项可以通过环境变量覆盖配置文件:
|
||||
|
||||
| 环境变量 | 对应配置项 |
|
||||
|----------|------------|
|
||||
| APP_NAME | app_name |
|
||||
| HOST | host |
|
||||
| PORT | port |
|
||||
| DEBUG | debug |
|
||||
| SECRET_KEY | secret_key |
|
||||
| API_PREFIX | api_prefix |
|
||||
| EXTERNAL_API_KEY | external_api_key |
|
||||
| CORS_ORIGINS | cors_origins |
|
||||
| WORKERS | workers |
|
||||
| DATABASE_URL | database.url |
|
||||
| REDIS_URL | redis.url |
|
||||
| MONITOR_ENABLED | monitor.enabled |
|
||||
| MONITOR_CHECK_INTERVAL | monitor.check_interval |
|
||||
|
||||
---
|
||||
|
||||
## 配置加载与保存流程
|
||||
|
||||
```
|
||||
启动时 (startup_event)
|
||||
│
|
||||
├──► load_config_from_file("config.json")
|
||||
│ │
|
||||
│ ▼
|
||||
│ 解析 JSON 配置
|
||||
│ │
|
||||
│ ▼
|
||||
│ 设置 Settings 各属性
|
||||
│ │
|
||||
│ ▼
|
||||
│ 初始化数据库连接
|
||||
│ │
|
||||
│ ▼
|
||||
│ 从数据库加载节点配置 (nodes 表)
|
||||
│ │
|
||||
│ ▼
|
||||
│ NodeManager.add_node() 注册节点
|
||||
│
|
||||
└──► register_builtin_plugins()
|
||||
|
||||
关闭时 (shutdown_event)
|
||||
│
|
||||
├──► monitor_service.stop()
|
||||
│
|
||||
└──► 保存配置到文件 (如需要)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 数据库表结构
|
||||
|
||||
### nodes 表
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| node_id | VARCHAR(50) | 节点唯一标识符 |
|
||||
| name | VARCHAR(100) | 节点显示名称 |
|
||||
| api_url | VARCHAR(255) | 节点 API 地址 |
|
||||
| api_key | VARCHAR(255) | 节点 API 密钥 |
|
||||
| enabled | BOOLEAN | 是否启用 |
|
||||
| description | TEXT | 节点描述 |
|
||||
| group | VARCHAR(50) | 节点分组 |
|
||||
| status | VARCHAR(20) | API 状态 |
|
||||
| wechat_status | VARCHAR(20) | 微信状态 |
|
||||
| is_healthy | BOOLEAN | 健康状态 |
|
||||
| created_at | TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | 更新时间 |
|
||||
|
||||
### webhook_urls 表
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | SERIAL | Webhook ID |
|
||||
| name | VARCHAR(100) | Webhook 名称 |
|
||||
| url | VARCHAR(500) | Webhook URL 地址 |
|
||||
| format | VARCHAR(20) | 消息格式 (bark/wechat) |
|
||||
| enabled | BOOLEAN | 是否启用 |
|
||||
| event_types | TEXT | 支持的事件类型 |
|
||||
| created_at | TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | 更新时间 |
|
||||
|
||||
### logs 表
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | SERIAL | 日志 ID |
|
||||
| timestamp | TIMESTAMP | 日志时间 |
|
||||
| level | VARCHAR(20) | 日志级别 |
|
||||
| source | VARCHAR(50) | 日志来源 |
|
||||
| message | TEXT | 日志消息 |
|
||||
|
||||
详细表结构请参阅 [DATABASE.md](./DATABASE.md)。
|
||||
@@ -0,0 +1,282 @@
|
||||
# ///
|
||||
# DATABASE.md
|
||||
# 描述:WXAuto Center 数据库设计文档
|
||||
# 作者:AI Generated
|
||||
# 创建日期:2026-04-05
|
||||
# 更新日期:2026-04-06
|
||||
# ///
|
||||
|
||||
# WXAuto Center 数据库设计文档
|
||||
|
||||
## 概述
|
||||
|
||||
本系统使用 PostgreSQL 数据库,通过 SQLAlchemy ORM 进行数据访问。数据库包含以下表:
|
||||
|
||||
| 表名 | 说明 |
|
||||
|------|------|
|
||||
| `nodes` | 节点配置表 |
|
||||
| `webhook_urls` | Webhook URL 表 |
|
||||
| `logs` | 日志表 |
|
||||
| `plugin_configs` | 插件配置表 |
|
||||
|
||||
## ER 图
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
│ nodes │ │ webhook_urls │
|
||||
├─────────────────┤ ├─────────────────┤
|
||||
│ node_id (PK) │ │ id (PK) │
|
||||
│ name │ │ name │
|
||||
│ api_url │ │ url │
|
||||
│ api_key │ │ format │
|
||||
│ enabled │ │ enabled │
|
||||
│ description │ │ event_types │
|
||||
│ group │ │ created_at │
|
||||
│ status │ │ updated_at │
|
||||
│ wechat_status │ └─────────────────┘
|
||||
│ is_healthy │
|
||||
│ health_message │
|
||||
│ created_at │
|
||||
│ updated_at │
|
||||
└─────────────────┘
|
||||
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
│ logs │ │ plugin_configs │
|
||||
├─────────────────┤ ├─────────────────┤
|
||||
│ id (PK) │ │ id (PK) │
|
||||
│ timestamp │ │ plugin_name │
|
||||
│ level │ │ config_json │
|
||||
│ source │ │ enabled │
|
||||
│ message │ │ created_at │
|
||||
└─────────────────┘ │ updated_at │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 表结构详解
|
||||
|
||||
### 1. nodes - 节点配置表
|
||||
|
||||
存储所有微信节点的信息。
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `node_id` | VARCHAR(50) | **PK** | 节点唯一标识 |
|
||||
| `name` | VARCHAR(100) | NOT NULL | 节点显示名称 |
|
||||
| `api_url` | VARCHAR(255) | NOT NULL | 节点 API 地址 |
|
||||
| `api_key` | VARCHAR(255) | NOT NULL | 节点 API 密钥 |
|
||||
| `enabled` | BOOLEAN | DEFAULT true | 是否启用 |
|
||||
| `description` | TEXT | DEFAULT '' | 节点描述 |
|
||||
| `group` | VARCHAR(50) | DEFAULT 'default' | 节点分组 |
|
||||
| `status` | VARCHAR(20) | DEFAULT 'inactive' | API 状态 |
|
||||
| `wechat_status` | VARCHAR(20) | DEFAULT 'online' | 微信状态 |
|
||||
| `is_healthy` | BOOLEAN | DEFAULT false | 健康检查状态 |
|
||||
| `health_message` | VARCHAR(255) | DEFAULT '' | 健康检查消息 |
|
||||
| `created_at` | TIMESTAMP | DEFAULT now | 创建时间 |
|
||||
| `updated_at` | TIMESTAMP | DEFAULT now | 更新时间 |
|
||||
|
||||
**状态值说明:**
|
||||
|
||||
| status 值 | 说明 |
|
||||
|------------|------|
|
||||
| `active` | API 正常响应 |
|
||||
| `inactive` | API 未响应 |
|
||||
| `error` | API 返回错误 |
|
||||
|
||||
| wechat_status 值 | 说明 |
|
||||
|------------------|------|
|
||||
| `online` | 微信已登录 |
|
||||
| `offline` | 微信未登录 |
|
||||
|
||||
**SQL:**
|
||||
```sql
|
||||
CREATE TABLE nodes (
|
||||
node_id VARCHAR(50) PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
api_url VARCHAR(255) NOT NULL,
|
||||
api_key VARCHAR(255) NOT NULL,
|
||||
enabled BOOLEAN DEFAULT true,
|
||||
description TEXT DEFAULT '',
|
||||
group VARCHAR(50) DEFAULT 'default',
|
||||
status VARCHAR(20) DEFAULT 'inactive',
|
||||
wechat_status VARCHAR(20) DEFAULT 'online',
|
||||
is_healthy BOOLEAN DEFAULT false,
|
||||
health_message VARCHAR(255) DEFAULT '',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. webhook_urls - Webhook URL 表
|
||||
|
||||
存储告警 webhook 配置。
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | INTEGER | **PK**, AUTO | 主键 |
|
||||
| `name` | VARCHAR(100) | NOT NULL | Webhook 名称 |
|
||||
| `url` | VARCHAR(500) | NOT NULL | Webhook URL |
|
||||
| `format` | VARCHAR(20) | DEFAULT 'bark' | 消息格式 |
|
||||
| `enabled` | BOOLEAN | DEFAULT true | 是否启用 |
|
||||
| `event_types` | TEXT | DEFAULT '' | 触发事件类型(逗号分隔) |
|
||||
| `created_at` | TIMESTAMP | DEFAULT now | 创建时间 |
|
||||
| `updated_at` | TIMESTAMP | DEFAULT now | 更新时间 |
|
||||
|
||||
**format 支持的格式:**
|
||||
- `bark` - Bark 推送格式
|
||||
- `wecom` - 企业微信
|
||||
- `dingtalk` - 钉钉
|
||||
- `feishu` - 飞书
|
||||
- `telegram` - Telegram
|
||||
- `serverchan` - Server酱
|
||||
|
||||
**event_types 支持的类型:**
|
||||
- `node_offline` - 节点离线
|
||||
- `node_error` - 节点错误
|
||||
- `wechat_offline` - 微信离线
|
||||
- `all` - 所有事件
|
||||
|
||||
---
|
||||
|
||||
### 3. logs - 日志表
|
||||
|
||||
存储系统运行日志。
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | INTEGER | **PK**, AUTO | 主键 |
|
||||
| `timestamp` | TIMESTAMP | DEFAULT now | 日志时间 |
|
||||
| `level` | VARCHAR(20) | NOT NULL | 日志级别 |
|
||||
| `source` | VARCHAR(50) | NOT NULL | 日志来源 |
|
||||
| `message` | TEXT | NOT NULL | 日志消息 |
|
||||
|
||||
**level 值:**
|
||||
- `INFO` - 信息
|
||||
- `WARNING` - 警告
|
||||
- `ERROR` - 错误
|
||||
- `SUCCESS` - 成功
|
||||
- `DEBUG` - 调试
|
||||
|
||||
---
|
||||
|
||||
### 4. plugin_configs - 插件配置表
|
||||
|
||||
存储插件的配置和启用状态。
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `id` | INTEGER | **PK**, AUTO | 主键 |
|
||||
| `plugin_name` | VARCHAR(100) | **UNIQUE**, NOT NULL | 插件名称 |
|
||||
| `config_json` | TEXT | DEFAULT '{}' | 插件配置(JSON格式) |
|
||||
| `enabled` | BOOLEAN | DEFAULT false | 是否启用 |
|
||||
| `created_at` | TIMESTAMP | DEFAULT now | 创建时间 |
|
||||
| `updated_at` | TIMESTAMP | DEFAULT now | 更新时间 |
|
||||
|
||||
**config_json 示例:**
|
||||
```json
|
||||
{
|
||||
"node_id": "wx1",
|
||||
"receiver": "文件传输助手",
|
||||
"cron": "0 8 * * *",
|
||||
"http_url": "https://api.example.com/news",
|
||||
"message_template": "📰 {title}\n{url}"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 数据库操作
|
||||
|
||||
### DatabaseService 主要方法
|
||||
|
||||
#### 节点操作
|
||||
```python
|
||||
# 获取所有节点
|
||||
db_service.get_all_nodes() -> List[Node]
|
||||
|
||||
# 获取指定节点
|
||||
db_service.get_node(node_id: str) -> Optional[Node]
|
||||
|
||||
# 添加节点
|
||||
db_service.add_node(node_id, name, api_url, api_key, description, group)
|
||||
|
||||
# 更新节点
|
||||
db_service.update_node(node_id, **kwargs) -> bool
|
||||
|
||||
# 删除节点
|
||||
db_service.delete_node(node_id) -> bool
|
||||
|
||||
# 获取启用的节点
|
||||
db_service.get_enabled_nodes() -> List[Node]
|
||||
```
|
||||
|
||||
#### Webhook 操作
|
||||
```python
|
||||
# 获取所有 Webhook
|
||||
db_service.get_all_webhooks() -> List[WebhookUrl]
|
||||
|
||||
# 获取启用的 Webhook
|
||||
db_service.get_enabled_webhooks() -> List[WebhookUrl]
|
||||
|
||||
# 添加 Webhook
|
||||
db_service.add_webhook(name, url, format, event_types) -> bool
|
||||
|
||||
# 更新 Webhook
|
||||
db_service.update_webhook(webhook_id, **kwargs) -> bool
|
||||
|
||||
# 删除 Webhook
|
||||
db_service.delete_webhook(webhook_id) -> bool
|
||||
```
|
||||
|
||||
#### 插件配置操作
|
||||
```python
|
||||
# 获取插件配置
|
||||
db_service.get_plugin_config(plugin_name: str) -> Optional[PluginConfig]
|
||||
|
||||
# 获取所有插件配置
|
||||
db_service.get_all_plugin_configs() -> List[PluginConfig]
|
||||
|
||||
# 保存插件配置
|
||||
db_service.save_plugin_config(plugin_name, config, enabled) -> bool
|
||||
|
||||
# 更新插件启用状态
|
||||
db_service.update_plugin_enabled(plugin_name, enabled) -> bool
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 索引
|
||||
|
||||
```sql
|
||||
-- nodes 表索引
|
||||
CREATE INDEX idx_nodes_enabled ON nodes(enabled);
|
||||
CREATE INDEX idx_nodes_group ON nodes(group);
|
||||
CREATE INDEX idx_nodes_status ON nodes(status);
|
||||
|
||||
-- webhook_urls 表索引
|
||||
CREATE INDEX idx_webhook_enabled ON webhook_urls(enabled);
|
||||
|
||||
-- logs 表索引
|
||||
CREATE INDEX idx_logs_timestamp ON logs(timestamp);
|
||||
CREATE INDEX idx_logs_level ON logs(level);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 迁移注意
|
||||
|
||||
如果数据库已存在,新增 `plugin_configs` 表:
|
||||
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS plugin_configs (
|
||||
id SERIAL PRIMARY KEY,
|
||||
plugin_name VARCHAR(100) UNIQUE NOT NULL,
|
||||
config_json TEXT DEFAULT '{}',
|
||||
enabled BOOLEAN DEFAULT false,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
```
|
||||
@@ -0,0 +1,770 @@
|
||||
# WXAuto Center 开发指南
|
||||
|
||||
## 开发环境搭建
|
||||
|
||||
### 环境要求
|
||||
|
||||
- Python 3.8+
|
||||
- Node.js 14+ (可选,用于前端开发)
|
||||
- Git
|
||||
|
||||
### 克隆与安装
|
||||
|
||||
```bash
|
||||
# 克隆项目
|
||||
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
|
||||
```
|
||||
|
||||
### 配置开发环境
|
||||
|
||||
```bash
|
||||
# 复制环境变量示例文件
|
||||
cp .env.example .env
|
||||
|
||||
# 编辑 .env 文件
|
||||
vim .env
|
||||
```
|
||||
|
||||
### 启动开发服务器
|
||||
|
||||
```bash
|
||||
# 方式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 应用的入口文件,负责:
|
||||
|
||||
1. 初始化 FastAPI 应用
|
||||
2. 配置 CORS 中间件
|
||||
3. 注册路由(nodes, messages, external, plugins)
|
||||
4. 处理启动/关闭事件
|
||||
|
||||
关键代码流程:
|
||||
|
||||
```python
|
||||
# 启动事件
|
||||
@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 进行配置管理:
|
||||
|
||||
```python
|
||||
# 配置模型
|
||||
Settings # 主配置类
|
||||
NodeConfig # 节点配置
|
||||
PluginConfig # 插件配置
|
||||
WebhookConfig # Webhook 配置
|
||||
MonitorConfig # 监控配置
|
||||
|
||||
# 配置管理器
|
||||
ConfigManager # 提供节点配置的增删改查
|
||||
|
||||
# 配置加载/保存
|
||||
load_config_from_file() # 从文件加载
|
||||
save_config_to_file() # 保存到文件
|
||||
```
|
||||
|
||||
### 节点管理器 (services/node_manager.py)
|
||||
|
||||
`NodeManager` 是核心服务类,负责与 WXAuto-HTTP-API 节点通信。
|
||||
|
||||
```python
|
||||
# 节点状态
|
||||
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` 提供日志记录和实时推送功能。
|
||||
|
||||
```python
|
||||
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. 创建插件类
|
||||
|
||||
```python
|
||||
# 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. 注册插件
|
||||
|
||||
```python
|
||||
# 在 builtin.py 或 main.py 中注册
|
||||
from plugins.base import PluginRegistry
|
||||
|
||||
my_plugin = MyCustomPlugin()
|
||||
my_plugin.initialize({"key": "value"})
|
||||
PluginRegistry.register(my_plugin)
|
||||
```
|
||||
|
||||
### 插件类型详解
|
||||
|
||||
#### DataSourcePlugin
|
||||
|
||||
用于从外部数据源获取数据:
|
||||
|
||||
```python
|
||||
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 消息处理:
|
||||
|
||||
```python
|
||||
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 调用
|
||||
|
||||
```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 调用
|
||||
|
||||
```bash
|
||||
# 添加节点
|
||||
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 调用
|
||||
|
||||
```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)
|
||||
|
||||
```javascript
|
||||
// 基础配置
|
||||
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 日志订阅
|
||||
|
||||
```javascript
|
||||
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();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 测试
|
||||
|
||||
### 运行测试
|
||||
|
||||
```bash
|
||||
# 安装测试依赖
|
||||
pip install pytest pytest-asyncio httpx
|
||||
|
||||
# 运行所有测试
|
||||
pytest
|
||||
|
||||
# 运行指定测试文件
|
||||
pytest tests/test_nodes.py
|
||||
|
||||
# 带详细输出
|
||||
pytest -v
|
||||
```
|
||||
|
||||
### 编写测试
|
||||
|
||||
```python
|
||||
# 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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 调试技巧
|
||||
|
||||
### 启用调试模式
|
||||
|
||||
```bash
|
||||
# 方式1:环境变量
|
||||
export DEBUG=true
|
||||
python main.py
|
||||
|
||||
# 方式2:命令行参数(如果支持)
|
||||
uvicorn main:app --reload --log-level debug
|
||||
|
||||
# 方式3:修改 .env
|
||||
DEBUG=true
|
||||
```
|
||||
|
||||
### 查看详细日志
|
||||
|
||||
系统内置日志服务,可通过 API 查看:
|
||||
|
||||
```bash
|
||||
# 获取最近日志
|
||||
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
|
||||
- 每个文件包含头部注释
|
||||
|
||||
### 注释要求
|
||||
|
||||
```python
|
||||
# ///
|
||||
# filename.py
|
||||
# 描述:该文件负责 [核心功能]
|
||||
# 作者:AI Generated
|
||||
# 创建日期:YYYY-MM-DD
|
||||
# ///
|
||||
|
||||
def function_name(param1, param2):
|
||||
"""
|
||||
函数简要描述
|
||||
|
||||
@param {type} param1 - 参数说明
|
||||
@return {type} 返回值说明
|
||||
@throws {异常类型} 异常情况说明
|
||||
"""
|
||||
pass
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 部署注意事项
|
||||
|
||||
### 生产环境配置
|
||||
|
||||
1. 修改 `secret_key` 为强密码
|
||||
2. 设置 `debug: false`
|
||||
3. 配置正确的 `cors_origins`
|
||||
4. 使用 HTTPS
|
||||
5. 配置防火墙规则
|
||||
|
||||
### 使用 Nginx 反向代理
|
||||
|
||||
```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 服务
|
||||
|
||||
```ini
|
||||
# /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
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo systemctl enable wxauto-center
|
||||
sudo systemctl start wxauto-center
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 关键实现细节
|
||||
|
||||
### 1. 健康检测机制 (is_node_healthy)
|
||||
|
||||
每次发送消息前,系统会调用此方法检测节点健康状态:
|
||||
|
||||
```python
|
||||
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. 消息发送流程
|
||||
|
||||
```python
|
||||
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. 监控告警流程
|
||||
|
||||
```python
|
||||
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, {...})
|
||||
```
|
||||
|
||||
**注意**:微信状态现在通过消息发送结果自动更新,不需要主动检测。
|
||||
@@ -0,0 +1,662 @@
|
||||
# WXAuto Center 业务流程文档
|
||||
|
||||
## 概述
|
||||
|
||||
本文档详细描述 WXAuto Center 的核心业务流程,包括消息发送流程、回调重置流程、监控告警流程、健康检测流程和日志发布订阅流程。
|
||||
|
||||
---
|
||||
|
||||
## 1. 节点标识系统
|
||||
|
||||
### 1.1 node_id 与 name 的区别
|
||||
|
||||
每个节点有两个标识:
|
||||
|
||||
| 字段 | 说明 | 示例 | 用途 |
|
||||
|------|------|------|------|
|
||||
| node_id | 节点唯一标识 | "wx1", "node_001" | API 调用、系统内部引用 |
|
||||
| name | 节点显示名称 | "微信1", "测试节点" | 界面展示、用户友好提示 |
|
||||
|
||||
### 1.2 节点数据模型
|
||||
|
||||
```json
|
||||
{
|
||||
"node_id": "wx1",
|
||||
"name": "微信1",
|
||||
"api_url": "http://192.168.20.18:5000",
|
||||
"api_key": "key",
|
||||
"enabled": true,
|
||||
"description": "",
|
||||
"group": "wechat",
|
||||
"status": "active",
|
||||
"wechat_status": "online",
|
||||
"is_healthy": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 消息发送流程
|
||||
|
||||
### 2.1 流程图
|
||||
|
||||
```
|
||||
外部请求
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ POST /api/v1/messages/send │
|
||||
│ 或 │
|
||||
│ POST /api/v1/external/send │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ check_node_health(node_id) │
|
||||
│ 调用 /api/wechat/initialize 检测微信状态 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
├──► 微信状态异常?
|
||||
│ │
|
||||
│ ▼ (是)
|
||||
│ 返回 HTTP 503
|
||||
│ "Node 'wx1' is not healthy..."
|
||||
│ │
|
||||
│ ▼
|
||||
│ 流程结束
|
||||
│
|
||||
▼ (否)
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ node_manager.send_message(node_id, who, msg, msg_type) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
├──► POST /api/wechat/initialize (初始化微信)
|
||||
│
|
||||
└──► POST /api/message/send (发送消息)
|
||||
│
|
||||
▼
|
||||
发送成功?
|
||||
│
|
||||
├──► 是 → wechat_status = "online"
|
||||
│ │
|
||||
│ ▼
|
||||
│ 返回成功响应
|
||||
│
|
||||
└──► 否 → wechat_status = "offline"
|
||||
│
|
||||
▼
|
||||
返回错误响应
|
||||
```
|
||||
|
||||
### 2.2 详细步骤说明
|
||||
|
||||
| 步骤 | 操作 | 说明 |
|
||||
|------|------|------|
|
||||
| 1 | 接收发送消息请求 | 解析 node_id, who, msg, msg_type |
|
||||
| 2 | 健康检测 | 调用 is_node_healthy() 检测节点 |
|
||||
| 3 | 初始化微信 | 调用 /api/wechat/initialize |
|
||||
| 4 | 发送消息 | 调用 /api/message/send |
|
||||
| 5 | 更新状态 | 根据发送结果更新 wechat_status |
|
||||
| 6 | 返回响应 | 返回发送结果给客户端 |
|
||||
|
||||
### 2.3 代码逻辑
|
||||
|
||||
```python
|
||||
async def send_message(node_id: str, who: str, msg: str, msg_type: str = "text"):
|
||||
# 1. 检查节点是否健康
|
||||
is_healthy, health_msg = await node_manager.is_node_healthy(node_id)
|
||||
if not is_healthy:
|
||||
raise HTTPException(
|
||||
status_code=503,
|
||||
detail=f"Node '{node_id}' is not healthy: {health_msg}"
|
||||
)
|
||||
|
||||
# 2. 初始化微信
|
||||
await node_manager.call_node_api(node_id, "/api/wechat/initialize", method="POST")
|
||||
|
||||
# 3. 发送消息
|
||||
result = await node_manager.call_node_api(
|
||||
node_id,
|
||||
"/api/message/send",
|
||||
method="POST",
|
||||
data={"receiver": who, "message": msg}
|
||||
)
|
||||
|
||||
# 4. 更新状态
|
||||
if result.get("code") == 0:
|
||||
node_manager.update_node_status(node_id, wechat_status="online")
|
||||
else:
|
||||
node_manager.update_node_status(node_id, wechat_status="offline")
|
||||
|
||||
return result
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 回调重置流程
|
||||
|
||||
### 3.1 流程图
|
||||
|
||||
```
|
||||
外部节点回调
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ POST /api/v1/callback/node/reset │
|
||||
│ 请求体: {"node_id": "wx1"} │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 调用 /api/wechat/initialize 初始化微信 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 调用 /api/message/send 发送检测消息到"文件传输助手" │
|
||||
│ receiver: "filehelper" │
|
||||
│ message: "WXAuto Center 检测消息" │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
检测结果
|
||||
│
|
||||
├──► 发送成功
|
||||
│ │
|
||||
│ ▼
|
||||
│ wechat_status = "online"
|
||||
│ │
|
||||
│ ▼
|
||||
│ 返回 {"success": true, "wechat_status": "online"}
|
||||
│
|
||||
└──► 发送失败
|
||||
│
|
||||
▼
|
||||
wechat_status = "offline"
|
||||
│
|
||||
▼
|
||||
返回 {"success": false, "wechat_status": "offline"}
|
||||
│
|
||||
▼
|
||||
MonitorService 检测到状态变化
|
||||
│
|
||||
▼
|
||||
触发 Webhook 告警 (wechat_offline)
|
||||
```
|
||||
|
||||
### 3.2 详细步骤说明
|
||||
|
||||
| 步骤 | 操作 | 说明 |
|
||||
|------|------|------|
|
||||
| 1 | 接收重置请求 | 解析 node_id |
|
||||
| 2 | 初始化微信 | 调用 /api/wechat/initialize |
|
||||
| 3 | 发送检测消息 | 发送消息到文件传输助手(filehelper) |
|
||||
| 4 | 判断结果 | 根据发送是否成功设置状态 |
|
||||
| 5 | 触发告警 | 状态变化时触发 Webhook |
|
||||
|
||||
### 3.3 回调接口说明
|
||||
|
||||
**POST /api/v1/callback/node/reset**
|
||||
|
||||
用于重置节点的微信状态。当微信掉线后,可以通过此接口重新检测微信状态。
|
||||
|
||||
**请求体**:
|
||||
```json
|
||||
{
|
||||
"node_id": "wx1"
|
||||
}
|
||||
```
|
||||
|
||||
**响应示例 - 成功**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "微信状态已重置",
|
||||
"data": {
|
||||
"node_id": "wx1",
|
||||
"wechat_status": "online",
|
||||
"check_result": "success"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**响应示例 - 失败**:
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "微信状态检测失败",
|
||||
"data": {
|
||||
"node_id": "wx1",
|
||||
"wechat_status": "offline",
|
||||
"check_result": "failed",
|
||||
"error": "Unknown error"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 监控告警流程
|
||||
|
||||
### 4.1 流程图
|
||||
|
||||
```
|
||||
MonitorService 启动
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ _monitor_loop() 定时循环 │
|
||||
│ 间隔: check_interval (默认 60 秒) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ _check_all_nodes() │
|
||||
│ 遍历所有节点 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
对每个节点执行 _check_node(node_id):
|
||||
│
|
||||
├──► api_check_enabled?
|
||||
│ │
|
||||
│ ▼ (是)
|
||||
│ check_node_status(node_id)
|
||||
│ │
|
||||
│ ▼
|
||||
│ API 状态变化?
|
||||
│ │
|
||||
│ ├──► 是 → 触发 Webhook (node_online/node_offline)
|
||||
│ │
|
||||
│ └──► 否 → 无操作
|
||||
│
|
||||
└──► wechat_check_enabled?
|
||||
│
|
||||
▼ (是)
|
||||
initialize_wechat(node_id)
|
||||
│
|
||||
▼
|
||||
get_wechat_status(node_id)
|
||||
│
|
||||
▼
|
||||
微信状态变化?
|
||||
│
|
||||
├──► 是 → 触发 Webhook (wechat_online/wechat_offline)
|
||||
│
|
||||
└──► 否 → 无操作
|
||||
```
|
||||
|
||||
### 4.2 支持的事件类型
|
||||
|
||||
| 事件类型 | 触发条件 | 消息内容 |
|
||||
|----------|----------|----------|
|
||||
| api_error | API 调用失败 | "API Error: {error}" |
|
||||
| wechat_offline | 微信状态变为 offline | "微信掉线" |
|
||||
| wechat_online | 微信状态变为 online/connected | "微信上线" |
|
||||
| node_offline | 节点 API 不可用 | "节点离线" |
|
||||
| node_online | 节点 API 恢复可用 | "节点在线" |
|
||||
|
||||
### 4.3 Webhook 消息格式
|
||||
|
||||
**企业微信格式**:
|
||||
```json
|
||||
{
|
||||
"msgtype": "text",
|
||||
"text": {
|
||||
"content": "【WXAuto Center 告警】\n事件类型: 微信掉线\n节点: wx1 (微信1)\n状态: offline\n时间: 2026-04-05 10:00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Bark 格式**:
|
||||
```json
|
||||
{
|
||||
"title": "WXAuto告警 - 微信掉线",
|
||||
"body": "wx1\n状态: offline\n时间: 2026-04-05 10:00:00",
|
||||
"icon": "https://..."
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 健康检测流程
|
||||
|
||||
### 5.1 流程图
|
||||
|
||||
```
|
||||
is_node_healthy(node_id) 调用
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ check_node_status(node_id) │
|
||||
│ 调用 GET /health 检测 API 可用性 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
API 状态检查
|
||||
│
|
||||
├──► API 不可用 → 返回 (False, "API status: {status}")
|
||||
│
|
||||
▼ (API 可用)
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ /api/wechat/initialize │
|
||||
│ 调用 POST /api/wechat/initialize 初始化微信 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
解析返回状态 (code, message, status)
|
||||
│
|
||||
├──► code != 0?
|
||||
│ │
|
||||
│ ├──► "无效"/"1400"/"拒绝访问"
|
||||
│ │ │
|
||||
│ │ ▼
|
||||
│ │ 返回 (False, "WeChat window invalid")
|
||||
│ │
|
||||
│ └──► 其他错误消息
|
||||
│ │
|
||||
│ ▼
|
||||
│ 返回 (False, "WeChat error: {message}")
|
||||
│
|
||||
├──► status not in ["connected", "online"]?
|
||||
│ │
|
||||
│ └──► 是 → 返回 (False, "WeChat status: {status}")
|
||||
│
|
||||
└──► 其他情况
|
||||
│
|
||||
▼
|
||||
返回 (True, "OK")
|
||||
```
|
||||
|
||||
### 5.2 健康检测判断逻辑
|
||||
|
||||
```python
|
||||
async def is_node_healthy(node_id: str) -> tuple[bool, str]:
|
||||
# 1. 检查 API 状态
|
||||
api_status = await self.check_node_status(node_id)
|
||||
if api_status != NodeStatus.ACTIVE:
|
||||
return False, f"API status: {api_status}"
|
||||
|
||||
# 2. 调用 /api/wechat/initialize 检测微信
|
||||
init_result = await self.call_node_api(node_id, "/api/wechat/initialize", method="POST")
|
||||
|
||||
# 3. 解析返回状态
|
||||
if not init_result.get("success"):
|
||||
return False, f"WeChat check failed: {init_result.get('error')}"
|
||||
|
||||
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"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 微信状态机
|
||||
|
||||
### 6.1 状态定义
|
||||
|
||||
| 状态 | 说明 | 可转换状态 |
|
||||
|------|------|------------|
|
||||
| online | 微信正常在线(默认/成功状态) | offline |
|
||||
| offline | 微信掉线或不可用 | online |
|
||||
|
||||
### 6.2 状态转换图
|
||||
|
||||
```
|
||||
┌──────────────┐
|
||||
│ online │
|
||||
│ (默认/成功) │
|
||||
└──────┬───────┘
|
||||
│
|
||||
发送消息失败
|
||||
或微信掉线检测
|
||||
│
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ offline │
|
||||
└──────┬───────┘
|
||||
│
|
||||
回调重置成功
|
||||
(文件传输助手检测)
|
||||
│
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ online │
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
### 6.3 状态转换场景
|
||||
|
||||
| 场景 | 原状态 | 新状态 | 触发条件 |
|
||||
|------|--------|--------|----------|
|
||||
| 消息发送成功 | online | online | code == 0 |
|
||||
| 消息发送失败 | online | offline | code != 0 |
|
||||
| 微信掉线 | online | offline | 监控检测到异常 |
|
||||
| 回调重置成功 | offline | online | 检测消息发送成功 |
|
||||
| 回调重置失败 | offline | offline | 检测消息发送失败 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 日志发布订阅流程
|
||||
|
||||
### 7.1 流程图
|
||||
|
||||
```
|
||||
业务操作调用
|
||||
│
|
||||
├──► log_service.info(message, source)
|
||||
├──► log_service.warning(message, source)
|
||||
├──► log_service.error(message, source)
|
||||
└──► log_service.success(message, source)
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ LogEntry 创建 │
|
||||
│ {timestamp, level, source, message} │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
├──► 存入 deque (本地缓存,最多 500 条)
|
||||
│
|
||||
└──► 推送到 SSE Queue
|
||||
│
|
||||
▼
|
||||
所有订阅者收到消息
|
||||
│
|
||||
▼
|
||||
unsubscribe() 取消订阅
|
||||
```
|
||||
|
||||
### 7.2 SSE 订阅示例
|
||||
|
||||
```javascript
|
||||
// 前端订阅日志流
|
||||
const eventSource = new EventSource('/api/v1/logs/stream');
|
||||
|
||||
eventSource.onmessage = (event) => {
|
||||
const logEntry = JSON.parse(event.data);
|
||||
console.log(`[${logEntry.level}] ${logEntry.message}`);
|
||||
};
|
||||
|
||||
eventSource.onerror = (error) => {
|
||||
console.error('SSE Error:', error);
|
||||
eventSource.close();
|
||||
};
|
||||
```
|
||||
|
||||
### 7.3 日志级别
|
||||
|
||||
| 级别 | 说明 | 使用场景 |
|
||||
|------|------|----------|
|
||||
| INFO | 信息 | 一般操作日志 |
|
||||
| WARNING | 警告 | 异常但可恢复 |
|
||||
| ERROR | 错误 | 操作失败 |
|
||||
| SUCCESS | 成功 | 操作成功确认 |
|
||||
|
||||
---
|
||||
|
||||
## 8. 批量操作流程
|
||||
|
||||
### 8.1 广播消息流程
|
||||
|
||||
```
|
||||
广播请求
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ POST /api/v1/messages/broadcast │
|
||||
│ 请求体: {node_ids, who, msg, msg_type} │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
node_ids 为空?
|
||||
│
|
||||
├──► 是 → 获取所有已启用节点
|
||||
│
|
||||
▼ (否)
|
||||
使用指定的 node_ids
|
||||
│
|
||||
▼
|
||||
对每个节点并行发送消息
|
||||
│
|
||||
├──► 节点1 → send_message() → 结果1
|
||||
├──► 节点2 → send_message() → 结果2
|
||||
└──► 节点N → send_message() → 结果N
|
||||
│
|
||||
▼
|
||||
汇总结果
|
||||
│
|
||||
▼
|
||||
返回批量结果
|
||||
```
|
||||
|
||||
### 8.2 批量发送流程
|
||||
|
||||
```
|
||||
批量请求
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ POST /api/v1/messages/batch │
|
||||
│ 请求体: {messages: [{node_id, who, msg, msg_type}, ...]} │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
验证消息列表
|
||||
│
|
||||
▼
|
||||
对每条消息并行发送
|
||||
│
|
||||
├──► 消息1 → send_message() → 结果1
|
||||
├──► 消息2 → send_message() → 结果2
|
||||
└──► 消息N → send_message() → 结果N
|
||||
│
|
||||
▼
|
||||
汇总结果
|
||||
│
|
||||
▼
|
||||
返回批量结果
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 插件执行流程
|
||||
|
||||
### 9.1 外部触发流程
|
||||
|
||||
```
|
||||
外部请求
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ POST /api/v1/external/trigger │
|
||||
│ 请求体: {source, event, data, auto_send, target, node_id} │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
获取插件
|
||||
│
|
||||
▼
|
||||
执行插件
|
||||
│
|
||||
├──► plugin.execute(event, data)
|
||||
│
|
||||
▼
|
||||
auto_send = true?
|
||||
│
|
||||
├──► 是 → 发送消息到 target
|
||||
│ │
|
||||
│ ▼
|
||||
│ 返回 {plugin_result, send_result}
|
||||
│
|
||||
└──► 否 → 返回 {plugin_result}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 完整状态流转图
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ 系统启动 │
|
||||
│ 节点创建 (wechat_status=online) │
|
||||
└─────────────────┬───────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────┐
|
||||
│ 正常运行 │
|
||||
│ wechat_status=online │
|
||||
└─────────────────┬───────────────────┘
|
||||
│
|
||||
┌─────────────────┴─────────────────┐
|
||||
│ │
|
||||
▼ ▼
|
||||
┌───────────────────────┐ ┌───────────────────────┐
|
||||
│ 消息发送成功 │ │ 消息发送失败 │
|
||||
│ wechat_status= │ │ wechat_status= │
|
||||
│ online │ │ offline │
|
||||
└───────────────────────┘ └───────────┬───────────┘
|
||||
│
|
||||
▼
|
||||
┌───────────────────────┐
|
||||
│ 调用回调重置接口 │
|
||||
│ POST /callback/node/ │
|
||||
│ reset │
|
||||
└───────────┬───────────┘
|
||||
│
|
||||
┌───────────────┴───────────────┐
|
||||
│ │
|
||||
▼ ▼
|
||||
┌───────────────────────┐ ┌───────────────────────┐
|
||||
│ 重置成功 │ │ 重置失败 │
|
||||
│ 发送检测消息成功 │ │ 发送检测消息失败 │
|
||||
│ wechat_status= │ │ wechat_status= │
|
||||
│ online │ │ offline │
|
||||
└───────────────────────┘ └───────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌───────────────────────┐
|
||||
│ 触发 Webhook 告警 │
|
||||
│ wechat_offline │
|
||||
└───────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 更新日志
|
||||
|
||||
| 日期 | 更新内容 |
|
||||
|------|----------|
|
||||
| 2026-04-05 | 创建 FLOWS.md 业务流程文档 |
|
||||
| 2026-04-05 | 添加消息发送流程图 |
|
||||
| 2026-04-05 | 添加回调重置流程图 |
|
||||
| 2026-04-05 | 添加监控告警流程图 |
|
||||
| 2026-04-05 | 添加健康检测流程图 |
|
||||
| 2026-04-05 | 添加微信状态机说明 |
|
||||
| 2026-04-05 | 添加日志发布订阅流程图 |
|
||||
@@ -0,0 +1,615 @@
|
||||
# WXAuto Center 模块索引文档
|
||||
|
||||
## 1. 模块概览
|
||||
|
||||
WXAuto Center 采用分层架构,主要分为以下模块:
|
||||
|
||||
| 层级 | 模块 | 路径 | 职责 |
|
||||
|------|------|------|------|
|
||||
| 接入层 | API Routes | `api/` | 处理 HTTP 请求,提供 RESTful 接口 |
|
||||
| 业务逻辑层 | Services | `services/` | 核心业务逻辑处理 |
|
||||
| 公共工具层 | Utils | `utils/` | 公共函数和依赖注入 |
|
||||
| 插件系统 | Plugins | `plugins/` | 扩展功能插件 |
|
||||
| 配置层 | Config | `config.py` | 系统配置管理 |
|
||||
| 入口 | Main | `main.py` | FastAPI 应用入口 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 模块详细说明
|
||||
|
||||
### 2.1 接入层 (API Layer)
|
||||
|
||||
#### api/nodes.py - 节点管理 API
|
||||
|
||||
**文件路径**:[nodes.py](../../wxauto_center/api/nodes.py)
|
||||
|
||||
**职责**:
|
||||
- 节点的增删改查 (CRUD)
|
||||
- 节点状态检测
|
||||
- 微信初始化
|
||||
- 节点启用/禁用
|
||||
- 获取好友列表、群列表、聊天消息
|
||||
|
||||
**主要端点**:
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | /nodes | 获取所有节点 |
|
||||
| GET | /nodes/{node_id} | 获取指定节点 |
|
||||
| POST | /nodes | 添加节点 |
|
||||
| PUT | /nodes/{node_id} | 更新节点 |
|
||||
| DELETE | /nodes/{node_id} | 删除节点 |
|
||||
| POST | /nodes/{node_id}/enable | 启用节点 |
|
||||
| POST | /nodes/{node_id}/disable | 禁用节点 |
|
||||
| GET | /nodes/{node_id}/status | 检查节点状态 |
|
||||
| GET | /nodes/{node_id}/wechat/status | 获取微信状态 |
|
||||
| POST | /nodes/{node_id}/wechat/initialize | 初始化微信 |
|
||||
|
||||
**依赖**:`services.node_manager`, `utils.require_api_key`
|
||||
|
||||
**节点标识说明**:所有接口使用 `node_id` 作为节点唯一标识。
|
||||
|
||||
---
|
||||
|
||||
#### api/messages.py - 消息管理 API
|
||||
|
||||
**文件路径**:[messages.py](../../wxauto_center/api/messages.py)
|
||||
|
||||
**职责**:
|
||||
- 发送消息
|
||||
- 发送群消息
|
||||
- 批量发送消息
|
||||
- 发送模板消息
|
||||
- 获取消息历史
|
||||
|
||||
**主要端点**:
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| POST | /messages/send | 发送消息 |
|
||||
| POST | /messages/send_group | 发送群消息 |
|
||||
| POST | /messages/batch | 批量发送 |
|
||||
| POST | /messages/template/{node_id}/{who} | 发送模板消息 |
|
||||
| GET | /messages/history/{node_id}/{chat_name} | 获取消息历史 |
|
||||
|
||||
**依赖**:`services.node_manager`, `utils.require_api_key`, `utils.check_node_health`
|
||||
|
||||
**说明**:已移除广播功能。
|
||||
|
||||
---
|
||||
|
||||
#### api/external.py - 外部扩展 API
|
||||
|
||||
**文件路径**:[external.py](../../wxauto_center/api/external.py)
|
||||
|
||||
**职责**:
|
||||
- 供外部系统调用的接口
|
||||
- 外部消息发送
|
||||
- 数据处理触发
|
||||
- 插件执行
|
||||
- AI 消息处理
|
||||
- Webhook 接收
|
||||
|
||||
**主要端点**:
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| POST | /external/send | 外部接口-发送消息 |
|
||||
| POST | /external/trigger | 外部接口-触发数据处理 |
|
||||
| POST | /external/plugin/execute | 外部接口-执行插件 |
|
||||
| GET | /external/plugins | 外部接口-获取插件列表 |
|
||||
| GET | /external/nodes | 外部接口-获取可用节点 |
|
||||
| POST | /external/ai/process | 外部接口-AI处理消息 |
|
||||
| POST | /external/webhook/{event} | 外部接口-Webhook接收 |
|
||||
|
||||
**认证方式**:`X-ExternalKey` Header
|
||||
|
||||
**依赖**:`services.node_manager`, `plugins.base.PluginRegistry`, `utils.require_external_key`
|
||||
|
||||
---
|
||||
|
||||
#### api/plugins.py - 插件管理 API
|
||||
|
||||
**文件路径**:[plugins.py](../../wxauto_center/api/plugins.py)
|
||||
|
||||
**职责**:
|
||||
- 插件注册和管理
|
||||
- 插件启用/禁用
|
||||
- 插件配置更新
|
||||
- 按类型获取插件
|
||||
|
||||
**主要端点**:
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | /plugins | 获取所有插件 |
|
||||
| GET | /plugins/{plugin_name} | 获取插件详情 |
|
||||
| POST | /plugins/{plugin_name}/enable | 启用插件 |
|
||||
| POST | /plugins/{plugin_name}/disable | 禁用插件 |
|
||||
| PUT | /plugins/{plugin_name}/config | 更新插件配置 |
|
||||
| POST | /plugins/{plugin_name}/execute | 执行插件 |
|
||||
| GET | /plugins/type/{plugin_type} | 按类型获取插件 |
|
||||
|
||||
**依赖**:`plugins.base.PluginRegistry`, `utils.require_api_key`
|
||||
|
||||
---
|
||||
|
||||
#### api/callback.py - 回调接口 API
|
||||
|
||||
**文件路径**:[callback.py](../../wxauto_center/api/callback.py)
|
||||
|
||||
**职责**:
|
||||
- 外部节点回调
|
||||
- 节点微信状态重置
|
||||
- 节点微信状态检测
|
||||
- 节点状态查询
|
||||
|
||||
**主要端点**:
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| POST | /callback/node/reset | 重置节点微信状态 |
|
||||
| POST | /callback/node/check | 检测节点微信状态 |
|
||||
| GET | /callback/node/{node_id}/status | 获取节点回调状态 |
|
||||
|
||||
**业务流程**:
|
||||
```
|
||||
1. 发送消息 → 失败 → wechat_status = offline
|
||||
2. 回调重置接口 → 发送检测消息 → 成功 → wechat_status = online
|
||||
3. 监控服务检测状态变化 → 触发Webhook告警
|
||||
```
|
||||
|
||||
**依赖**:`services.node_manager`, `services.log_service`, `utils.require_api_key`
|
||||
|
||||
---
|
||||
|
||||
### 2.2 业务逻辑层 (Service Layer)
|
||||
|
||||
#### services/node_manager.py - 节点管理服务
|
||||
|
||||
**文件路径**:[node_manager.py](../../wxauto_center/services/node_manager.py)
|
||||
|
||||
**职责**:
|
||||
- 节点注册和注销
|
||||
- 节点通信管理
|
||||
- API 调用封装
|
||||
- 消息发送
|
||||
- 节点状态检测
|
||||
|
||||
**核心类**:
|
||||
|
||||
| 类名 | 说明 |
|
||||
|------|------|
|
||||
| NodeStatus | 节点状态枚举 (ACTIVE, INACTIVE, ERROR) |
|
||||
| Node | 节点数据模型(包含 node_id 和 name) |
|
||||
| NodeManager | 节点管理服务类 |
|
||||
|
||||
**主要方法**:
|
||||
|
||||
| 方法 | 说明 |
|
||||
|------|------|
|
||||
| add_node() | 添加节点 |
|
||||
| remove_node(node_id) | 删除节点 |
|
||||
| get_node(node_id) | 获取节点 |
|
||||
| get_all_nodes() | 获取所有节点 |
|
||||
| get_enabled_nodes() | 获取已启用节点 |
|
||||
| check_node_status(node_id) | 检测节点状态 |
|
||||
| is_node_healthy(node_id) | 判断节点是否健康 |
|
||||
| call_node_api() | 调用节点 API |
|
||||
| send_message(node_id, who, msg, msg_type) | 发送消息 |
|
||||
| send_message_to_group(node_id, group_name, msg, msg_type) | 发送群消息 |
|
||||
|
||||
**内部方法**:
|
||||
|
||||
| 方法 | 说明 |
|
||||
|------|------|
|
||||
| _send_message_internal() | 发送消息的内部方法 (复用逻辑) |
|
||||
|
||||
**依赖**:`services.log_service`
|
||||
|
||||
---
|
||||
|
||||
#### services/monitor_service.py - 监控服务
|
||||
|
||||
**文件路径**:[monitor_service.py](../../wxauto_center/services/monitor_service.py)
|
||||
|
||||
**职责**:
|
||||
- 定时检测节点状态
|
||||
- 检测 API 状态变化
|
||||
- 检测微信状态变化
|
||||
- 触发 Webhook 告警
|
||||
|
||||
**主要方法**:
|
||||
|
||||
| 方法 | 说明 |
|
||||
|------|------|
|
||||
| start() | 启动监控服务 |
|
||||
| stop() | 停止监控服务 |
|
||||
| get_last_status() | 获取节点最后状态 |
|
||||
| get_all_status() | 获取所有节点状态 |
|
||||
|
||||
**内部方法**:
|
||||
|
||||
| 方法 | 说明 |
|
||||
|------|------|
|
||||
| _monitor_loop() | 监控主循环 |
|
||||
| _check_all_nodes() | 检测所有节点 |
|
||||
| _check_node() | 检测单个节点 |
|
||||
| _send_webhook() | 发送 Webhook 通知 |
|
||||
|
||||
**依赖**:`config.get_settings`, `services.node_manager`, `services.log_service`
|
||||
|
||||
---
|
||||
|
||||
#### services/log_service.py - 日志服务
|
||||
|
||||
**文件路径**:[log_service.py](../../wxauto_center/services/log_service.py)
|
||||
|
||||
**职责**:
|
||||
- 日志记录
|
||||
- 日志缓存 (deque,最多 500 条)
|
||||
- SSE 实时推送
|
||||
- 发布订阅模式
|
||||
- Redis 缓存支持
|
||||
- 文件持久化 (logs/app.log)
|
||||
|
||||
**日志级别**:INFO, WARNING, ERROR, SUCCESS
|
||||
|
||||
**主要方法**:
|
||||
|
||||
| 方法 | 说明 |
|
||||
|------|------|
|
||||
| info() | 记录 INFO 日志 |
|
||||
| warning() | 记录 WARNING 日志 |
|
||||
| error() | 记录 ERROR 日志 |
|
||||
| success() | 记录 SUCCESS 日志 |
|
||||
| subscribe() | 订阅日志流 |
|
||||
| unsubscribe() | 取消订阅 |
|
||||
| get_recent_logs() | 获取最近日志 |
|
||||
| get_all_logs() | 获取所有日志 |
|
||||
|
||||
---
|
||||
|
||||
#### services/queue_service.py - 消息队列服务
|
||||
|
||||
**文件路径**:[queue_service.py](../../wxauto_center/services/queue_service.py)
|
||||
|
||||
**职责**:
|
||||
- 消息队列管理
|
||||
- Redis 后端支持(可选)
|
||||
- 本地队列回退
|
||||
- 异步任务处理
|
||||
|
||||
**队列名称**:
|
||||
|
||||
| 队列名 | 说明 |
|
||||
|--------|------|
|
||||
| MESSAGE_SEND | 消息发送队列 |
|
||||
| MESSAGE_BROADCAST | 消息广播队列(已废弃) |
|
||||
|
||||
**主要方法**:
|
||||
|
||||
| 方法 | 说明 |
|
||||
|------|------|
|
||||
| enqueue() | 入队操作 |
|
||||
| dequeue() | 出队操作(异步) |
|
||||
| get_queue_length() | 获取队列长度 |
|
||||
| start_worker() | 启动工作进程 |
|
||||
| stop_worker() | 停止工作进程 |
|
||||
|
||||
**依赖**:Redis (可选),若 Redis 不可用则使用本地 asyncio.Queue
|
||||
|
||||
---
|
||||
|
||||
### 2.3 公共工具层 (Utils Layer)
|
||||
|
||||
#### utils/common.py - 公共函数
|
||||
|
||||
**文件路径**:[common.py](../../wxauto_center/utils/common.py)
|
||||
|
||||
**职责**:
|
||||
- API Key 验证依赖 (require_api_key)
|
||||
- External Key 验证依赖 (require_external_key)
|
||||
|
||||
**主要函数**:
|
||||
|
||||
| 函数名 | 说明 |
|
||||
|--------|------|
|
||||
| require_api_key | API Key 验证依赖,用于 X-API-Key Header |
|
||||
| require_external_key | External Key 验证依赖,用于 X-ExternalKey Header |
|
||||
|
||||
**使用示例**:
|
||||
|
||||
```python
|
||||
from utils import require_api_key
|
||||
|
||||
@router.post("/endpoint")
|
||||
async def endpoint(_=Depends(require_api_key)):
|
||||
# 处理请求
|
||||
pass
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### utils/helpers.py - 业务辅助函数
|
||||
|
||||
**文件路径**:[helpers.py](../../wxauto_center/utils/helpers.py)
|
||||
|
||||
**职责**:
|
||||
- 节点健康检查
|
||||
- 响应构建
|
||||
- 结果解析
|
||||
|
||||
**主要函数**:
|
||||
|
||||
| 函数名 | 说明 |
|
||||
|--------|------|
|
||||
| check_node_health() | 检查节点健康状态,不健康则抛 503 异常 |
|
||||
| build_success_response() | 构建成功响应 |
|
||||
| build_error_response() | 构建错误响应 |
|
||||
| parse_node_result() | 解析节点 API 调用结果 |
|
||||
|
||||
---
|
||||
|
||||
### 2.4 插件系统 (Plugin Layer)
|
||||
|
||||
#### plugins/base.py - 插件基类
|
||||
|
||||
**文件路径**:[base.py](../../wxauto_center/plugins/base.py)
|
||||
|
||||
**职责**:
|
||||
- 定义插件接口
|
||||
- 插件注册表
|
||||
|
||||
**核心类**:
|
||||
|
||||
| 类名 | 说明 |
|
||||
|------|------|
|
||||
| PluginType | 插件类型枚举 |
|
||||
| PluginBase | 插件基类 |
|
||||
| MessageHandlerPlugin | 消息处理插件基类 |
|
||||
| DataSourcePlugin | 数据源插件基类 |
|
||||
| ActionTriggerPlugin | 动作触发插件基类 |
|
||||
| AIAgentPlugin | AI 智能体插件基类 |
|
||||
| PluginRegistry | 插件注册表 |
|
||||
|
||||
**PluginType 枚举值**:
|
||||
- MESSAGE_HANDLER = "message_handler"
|
||||
- DATA_SOURCE = "data_source"
|
||||
- ACTION_TRIGGER = "action_trigger"
|
||||
- AI_AGENT = "ai_agent"
|
||||
- CUSTOM = "custom"
|
||||
|
||||
---
|
||||
|
||||
#### plugins/builtin.py - 内置插件
|
||||
|
||||
**文件路径**:[builtin.py](../../wxauto_center/plugins/builtin.py)
|
||||
|
||||
**内置插件**:
|
||||
|
||||
| 插件名 | 类名 | 说明 |
|
||||
|--------|------|------|
|
||||
| http_data_source | HTTPDataSourcePlugin | HTTP 数据源插件,从外部 API 获取数据 |
|
||||
| database_query | DatabaseQueryPlugin | 数据库查询插件 (预留) |
|
||||
| webhook_trigger | WebhookTriggerPlugin | Webhook 触发器 |
|
||||
| simple_ai_agent | SimpleAIAgentPlugin | 简单 AI 智能体 |
|
||||
|
||||
**注册函数**:`register_builtin_plugins()`
|
||||
|
||||
---
|
||||
|
||||
### 2.5 配置层 (Config Layer)
|
||||
|
||||
#### config.py - 配置管理
|
||||
|
||||
**文件路径**:[config.py](../../wxauto_center/config.py)
|
||||
|
||||
**职责**:
|
||||
- 系统配置管理
|
||||
- 配置文件读写
|
||||
- 多环境支持
|
||||
|
||||
**核心配置类**:
|
||||
|
||||
| 类名 | 说明 |
|
||||
|------|------|
|
||||
| NodeConfig | 节点配置 |
|
||||
| PluginConfig | 插件配置 |
|
||||
| WebhookConfig | Webhook 配置 |
|
||||
| MonitorConfig | 监控配置 |
|
||||
| Settings | 应用设置 (继承 BaseSettings) |
|
||||
| ConfigManager | 配置管理器 |
|
||||
|
||||
**主要函数**:
|
||||
|
||||
| 函数名 | 说明 |
|
||||
|--------|------|
|
||||
| get_settings() | 获取全局设置单例 |
|
||||
| update_settings() | 更新设置 |
|
||||
| load_config_from_file() | 从文件加载配置 |
|
||||
| save_config_to_file() | 保存配置到文件 |
|
||||
|
||||
**ConfigManager 方法**:
|
||||
|
||||
| 方法 | 说明 |
|
||||
|------|------|
|
||||
| get_node() | 获取节点配置 |
|
||||
| get_all_nodes() | 获取所有节点配置 |
|
||||
| get_enabled_nodes() | 获取已启用节点配置 |
|
||||
| add_node() | 添加节点配置 |
|
||||
| update_node() | 更新节点配置 |
|
||||
| remove_node() | 删除节点配置 |
|
||||
| save_config() | 保存配置 |
|
||||
| load_config() | 加载配置 |
|
||||
|
||||
---
|
||||
|
||||
### 2.6 入口 (Main)
|
||||
|
||||
#### main.py - 应用入口
|
||||
|
||||
**文件路径**:[main.py](../../wxauto_center/main.py)
|
||||
|
||||
**职责**:
|
||||
- FastAPI 应用初始化
|
||||
- 中间件配置
|
||||
- 路由注册
|
||||
- 启动/关闭事件处理
|
||||
- 配置管理 API
|
||||
- 监控状态 API
|
||||
- 日志流 API
|
||||
|
||||
---
|
||||
|
||||
## 3. 模块依赖关系
|
||||
|
||||
```
|
||||
┌─────────────┐
|
||||
│ main.py │
|
||||
└──────┬──────┘
|
||||
│
|
||||
┌─────────────────┼─────────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌─────────┐ ┌─────────┐ ┌─────────┐
|
||||
│ config │ │ api/* │ │ services│
|
||||
└────┬────┘ └────┬────┘ └────┬────┘
|
||||
│ │ │
|
||||
│ ▼ ▼
|
||||
│ ┌───────────┐ ┌─────────┐
|
||||
│ │ utils/* │ │plugins/*│
|
||||
│ └───────────┘ └─────────┘
|
||||
│ │ │
|
||||
└─────────────────┼─────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────┐
|
||||
│ external │
|
||||
│ (WXAuto-HTTP │
|
||||
│ -API) │
|
||||
└─────────────┘
|
||||
```
|
||||
|
||||
**依赖详解**:
|
||||
|
||||
| 模块 | 被依赖 | 依赖 |
|
||||
|------|--------|------|
|
||||
| main.py | - | config, api, services, plugins |
|
||||
| config.py | api, services, main | pydantic, pydantic_settings |
|
||||
| api/* | main | services, plugins, utils, config |
|
||||
| services/* | api | config, log_service |
|
||||
| utils/* | api | config |
|
||||
| plugins/* | api, main | httpx |
|
||||
| log_service | services | - |
|
||||
|
||||
---
|
||||
|
||||
## 4. 代码导览
|
||||
|
||||
### 4.1 新增代码路径
|
||||
|
||||
重构后新增的公共模块:
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| [utils/__init__.py](../../wxauto_center/utils/__init__.py) | 工具模块导出 |
|
||||
| [utils/common.py](../../wxauto_center/utils/common.py) | API Key 验证依赖 |
|
||||
| [utils/helpers.py](../../wxauto_center/utils/helpers.py) | 业务辅助函数 |
|
||||
|
||||
### 4.2 重构变更
|
||||
|
||||
#### 删除的重复代码
|
||||
|
||||
以下文件中删除了重复定义的 `require_api_key` 函数:
|
||||
|
||||
- `api/nodes.py` - 现在从 `utils` 导入
|
||||
- `api/messages.py` - 现在从 `utils` 导入
|
||||
- `api/external.py` - 现在从 `utils` 导入
|
||||
- `api/plugins.py` - 现在从 `utils` 导入
|
||||
- `api/callback.py` - 现在从 `utils` 导入
|
||||
|
||||
#### 重构的方法
|
||||
|
||||
| 文件 | 原方法 | 新方法 |
|
||||
|------|--------|--------|
|
||||
| services/node_manager.py | send_message() 和 send_message_to_group() 重复代码 | 新增 _send_message_internal() 内部方法 |
|
||||
| api/callback.py | reset_node_wechat_status() 和 check_node_wechat_status() 重复逻辑 | 新增 _check_wechat_and_update_status() 公共函数 |
|
||||
|
||||
### 4.3 代码审计指南
|
||||
|
||||
#### 审计要点
|
||||
|
||||
1. **API Key 验证**
|
||||
- 所有 API 端点必须使用 `Depends(require_api_key)` 或 `Depends(require_external_key)`
|
||||
- 检查 `X-API-Key` 和 `X-ExternalKey` 是否正确使用
|
||||
|
||||
2. **节点健康检查**
|
||||
- 发送消息前必须调用 `check_node_health()`
|
||||
- 使用 `utils.check_node_health` 而非直接调用 `node_manager.is_node_healthy`
|
||||
|
||||
3. **配置保存**
|
||||
- 修改节点配置后必须调用 `save_nodes_config()` 保存
|
||||
- 修改全局配置后必须调用 `save_config_to_file()` 保存
|
||||
|
||||
4. **错误处理**
|
||||
- 使用 `build_success_response()` 和 `build_error_response()` 构建响应
|
||||
- 节点不存在时抛出 `HTTPException(status_code=404)`
|
||||
|
||||
5. **异步处理**
|
||||
- 所有 `node_manager` 方法都是异步的,使用 `await`
|
||||
- API 端点需要 `async def`
|
||||
|
||||
---
|
||||
|
||||
## 5. 模块索引
|
||||
|
||||
### 5.1 文件快速查找
|
||||
|
||||
| 功能 | 文件路径 |
|
||||
|------|----------|
|
||||
| API Key 验证 | [utils/common.py](../../wxauto_center/utils/common.py) |
|
||||
| 节点健康检查 | [utils/helpers.py](../../wxauto_center/utils/helpers.py) |
|
||||
| 节点管理 | [services/node_manager.py](../../wxauto_center/services/node_manager.py) |
|
||||
| 状态监控 | [services/monitor_service.py](../../wxauto_center/services/monitor_service.py) |
|
||||
| 日志服务 | [services/log_service.py](../../wxauto_center/services/log_service.py) |
|
||||
| 节点 API | [api/nodes.py](../../wxauto_center/api/nodes.py) |
|
||||
| 消息 API | [api/messages.py](../../wxauto_center/api/messages.py) |
|
||||
| 外部 API | [api/external.py](../../wxauto_center/api/external.py) |
|
||||
| 插件 API | [api/plugins.py](../../wxauto_center/api/plugins.py) |
|
||||
| 回调 API | [api/callback.py](../../wxauto_center/api/callback.py) |
|
||||
| 插件基类 | [plugins/base.py](../../wxauto_center/plugins/base.py) |
|
||||
| 内置插件 | [plugins/builtin.py](../../wxauto_center/plugins/builtin.py) |
|
||||
| 配置管理 | [config.py](../../wxauto_center/config.py) |
|
||||
| 应用入口 | [main.py](../../wxauto_center/main.py) |
|
||||
|
||||
### 5.2 类和函数查找
|
||||
|
||||
| 类/函数 | 文件 | 行号 |
|
||||
|---------|------|------|
|
||||
| NodeStatus | [node_manager.py](../../wxauto_center/services/node_manager.py#L15) | L15 |
|
||||
| Node | [node_manager.py](../../wxauto_center/services/node_manager.py#L21) | L21 |
|
||||
| NodeManager | [node_manager.py](../../wxauto_center/services/node_manager.py#L46) | L46 |
|
||||
| MonitorService | [monitor_service.py](../../wxauto_center/services/monitor_service.py#L18) | L18 |
|
||||
| LogService | [log_service.py](../../wxauto_center/services/log_service.py#L14) | L14 |
|
||||
| PluginBase | [base.py](../../wxauto_center/plugins/base.py#L21) | L21 |
|
||||
| PluginRegistry | [base.py](../../wxauto_center/plugins/base.py#L92) | L92 |
|
||||
| require_api_key | [common.py](../../wxauto_center/utils/common.py#L10) | L10 |
|
||||
| require_external_key | [common.py](../../wxauto_center/utils/common.py#L30) | L30 |
|
||||
| check_node_health | [helpers.py](../../wxauto_center/utils/helpers.py#L20) | L20 |
|
||||
| ConfigManager | [config.py](../../wxauto_center/config.py#L148) | L148 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 更新日志
|
||||
|
||||
| 日期 | 更新内容 |
|
||||
|------|----------|
|
||||
| 2026-04-05 | 更新 API 路径,将 node_name 替换为 node_id |
|
||||
| 2026-04-05 | 重构代码,新增 utils 模块,抽取公共函数 |
|
||||
| 2026-04-05 | 新增 MODULES.md 模块索引文档 |
|
||||
| 2026-04-05 | 更新 API.md,添加回调接口文档 |
|
||||
| 2026-04-05 | 更新 ARCHITECTURE.md,添加回调流程图和微信状态机 |
|
||||
| 2026-04-05 | 新增 QueueService 消息队列服务模块 |
|
||||
| 2026-04-05 | 更新 LogService 支持 Redis 缓存和文件持久化 |
|
||||
| 2026-04-05 | 移除广播功能相关文档 |
|
||||
@@ -0,0 +1,615 @@
|
||||
# ///
|
||||
# PLUGIN.md
|
||||
# 描述:插件系统开发指南
|
||||
# 作者:User
|
||||
# 创建日期:2026-04-05
|
||||
# 更新日期:2026-04-07
|
||||
# ///
|
||||
|
||||
# WXAuto Center 插件系统开发指南
|
||||
|
||||
## 目录
|
||||
|
||||
1. [概述](#概述)
|
||||
2. [插件类型](#插件类型)
|
||||
3. [创建插件](#创建插件)
|
||||
4. [表单化配置系统](#表单化配置系统)
|
||||
5. [插件通知系统](#插件通知系统)
|
||||
6. [热加载插件](#热加载插件)
|
||||
7. [内置插件](#内置插件)
|
||||
8. [高级多节点推送插件](#高级多节点推送插件)
|
||||
9. [插件管理API](#插件管理api)
|
||||
10. [前端使用](#前端使用)
|
||||
11. [最佳实践](#最佳实践)
|
||||
12. [目录结构](#目录结构)
|
||||
13. [生命周期](#生命周期)
|
||||
|
||||
---
|
||||
|
||||
## 概述
|
||||
|
||||
WXAuto Center 采用模块化插件架构,支持热插拔功能扩展。开发者可以创建自定义插件来处理消息、数据源、定时任务等。
|
||||
|
||||
### 核心组件
|
||||
|
||||
| 组件 | 说明 |
|
||||
|------|------|
|
||||
| `PluginBase` | 所有插件的基类 |
|
||||
| `ScheduledTaskPlugin` | 定时任务插件基类(含通知功能) |
|
||||
| `PluginRegistry` | 插件注册表,管理所有插件 |
|
||||
| `PluginType` | 插件类型枚举 |
|
||||
| `PluginConfigSchema` | 表单化配置Schema系统 |
|
||||
| `HotReloadPluginLoader` | 热加载服务,监控插件目录变化 |
|
||||
| `plugin_notification_service` | 插件通知服务 |
|
||||
|
||||
---
|
||||
|
||||
## 插件类型
|
||||
|
||||
| 类型 | 值 | 说明 |
|
||||
|------|-----|------|
|
||||
| `MESSAGE_HANDLER` | `message_handler` | 消息处理器,用于自动回复、消息过滤 |
|
||||
| `DATA_SOURCE` | `data_source` | 数据源,用于获取天气、新闻、股票等 |
|
||||
| `ACTION_TRIGGER` | `action_trigger` | 动作触发器,用于Webhook回调、定时任务 |
|
||||
| `AI_AGENT` | `ai_agent` | AI智能体,用于LLM对话、智能回复 |
|
||||
| `SCHEDULED_TASK` | `scheduled_task` | 定时任务,执行周期性操作 |
|
||||
| `HTTP_SCHEDULED_SENDER` | `http_scheduled_sender` | 定时HTTP推送,定时请求API并发送结果 |
|
||||
| `CUSTOM` | `custom` | 自定义类型 |
|
||||
|
||||
---
|
||||
|
||||
## 创建插件
|
||||
|
||||
### 基础结构
|
||||
|
||||
```python
|
||||
# ///
|
||||
# my_plugin.py
|
||||
# 描述:我的自定义插件
|
||||
# ///
|
||||
|
||||
from plugins.base import PluginBase, PluginType
|
||||
|
||||
class MyPlugin(PluginBase):
|
||||
plugin_name = "my_plugin"
|
||||
plugin_version = "1.0.0"
|
||||
plugin_type = PluginType.CUSTOM
|
||||
plugin_description = "我的自定义插件"
|
||||
plugin_author = "开发者名称"
|
||||
|
||||
def initialize(self, config: dict) -> bool:
|
||||
self.config = config
|
||||
return True
|
||||
|
||||
def execute(self, params: dict) -> dict:
|
||||
return {"success": True, "result": "done"}
|
||||
```
|
||||
|
||||
### 定时任务插件
|
||||
|
||||
```python
|
||||
# ///
|
||||
# my_scheduled_plugin.py
|
||||
# 描述:定时任务插件示例
|
||||
# ///
|
||||
|
||||
from plugins.base import ScheduledTaskPlugin
|
||||
from plugins.plugin_config_schema import (
|
||||
PluginConfigSchema, ConfigSection, ConfigField, FieldType
|
||||
)
|
||||
|
||||
def get_config_schema() -> PluginConfigSchema:
|
||||
schema = PluginConfigSchema("my_scheduled_plugin")
|
||||
schema.add_section(ConfigSection(
|
||||
name="basic",
|
||||
label="基本设置",
|
||||
fields=[
|
||||
ConfigField(
|
||||
name="cron",
|
||||
label="执行周期",
|
||||
field_type=FieldType.CRON,
|
||||
default="*/5 * * * *"
|
||||
),
|
||||
ConfigField(
|
||||
name="enabled",
|
||||
label="启用插件",
|
||||
field_type=FieldType.BOOLEAN,
|
||||
default=False
|
||||
)
|
||||
]
|
||||
))
|
||||
return schema
|
||||
|
||||
class MyScheduledPlugin(ScheduledTaskPlugin):
|
||||
plugin_name = "my_scheduled_plugin"
|
||||
plugin_version = "1.0.0"
|
||||
plugin_description = "定时任务插件"
|
||||
plugin_author = "开发者"
|
||||
config_schema = staticmethod(get_config_schema)
|
||||
|
||||
def get_cron_expression(self) -> str:
|
||||
return self.cron_expression
|
||||
|
||||
def should_run_and_get_next(self) -> tuple:
|
||||
return True, None
|
||||
|
||||
def run_task(self) -> dict:
|
||||
self.notify("任务完成", "定时任务执行成功")
|
||||
return {"success": True}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 表单化配置系统
|
||||
|
||||
### 字段类型
|
||||
|
||||
| 类型 | 值 | 说明 | 对应UI |
|
||||
|------|-----|------|--------|
|
||||
| `STRING` | `string` | 文本输入 | input[type=text] |
|
||||
| `PASSWORD` | `password` | 密码输入 | input[type=password] |
|
||||
| `NUMBER` | `number` | 数字输入 | input[type=number] |
|
||||
| `BOOLEAN` | `boolean` | 开关 | checkbox |
|
||||
| `SELECT` | `select` | 下拉选择 | select |
|
||||
| `TEXTAREA` | `textarea` | 多行文本 | textarea |
|
||||
| `CRON` | `cron` | Cron表达式 | input[type=text] |
|
||||
|
||||
### 配置示例
|
||||
|
||||
```python
|
||||
from plugins.plugin_config_schema import (
|
||||
PluginConfigSchema, ConfigSection, ConfigField, FieldType
|
||||
)
|
||||
|
||||
def get_config_schema() -> PluginConfigSchema:
|
||||
schema = PluginConfigSchema("my_plugin")
|
||||
|
||||
schema.add_section(ConfigSection(
|
||||
name="basic",
|
||||
label="基本设置",
|
||||
fields=[
|
||||
ConfigField(
|
||||
name="cron",
|
||||
label="执行周期",
|
||||
field_type=FieldType.CRON,
|
||||
required=True,
|
||||
default="*/5 * * * *",
|
||||
description="Cron表达式,如 */5 * * * *"
|
||||
),
|
||||
ConfigField(
|
||||
name="node_id",
|
||||
label="节点ID",
|
||||
field_type=FieldType.STRING,
|
||||
required=True,
|
||||
default="wx1"
|
||||
),
|
||||
ConfigField(
|
||||
name="receiver",
|
||||
label="接收人",
|
||||
field_type=FieldType.STRING,
|
||||
required=True
|
||||
),
|
||||
ConfigField(
|
||||
name="timeout",
|
||||
label="超时时间",
|
||||
field_type=FieldType.NUMBER,
|
||||
default=15,
|
||||
min_value=5,
|
||||
max_value=60
|
||||
),
|
||||
ConfigField(
|
||||
name="enabled",
|
||||
label="启用插件",
|
||||
field_type=FieldType.BOOLEAN,
|
||||
default=False
|
||||
)
|
||||
]
|
||||
))
|
||||
|
||||
return schema
|
||||
```
|
||||
|
||||
### API 调用
|
||||
|
||||
```bash
|
||||
# 获取插件表单Schema
|
||||
curl http://localhost:8080/api/v1/plugins/{plugin_name}/schema \
|
||||
-H "X-API-Key: your-external-api-key"
|
||||
|
||||
# 响应示例
|
||||
{
|
||||
"success": true,
|
||||
"schema": {
|
||||
"plugin_name": "my_plugin",
|
||||
"sections": [
|
||||
{
|
||||
"name": "basic",
|
||||
"label": "基本设置",
|
||||
"fields": [
|
||||
{"name": "cron", "label": "执行周期", "type": "cron", ...}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"has_form": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 插件通知系统
|
||||
|
||||
所有继承 `ScheduledTaskPlugin` 的插件都可以使用通知功能。
|
||||
|
||||
### 使用方法
|
||||
|
||||
```python
|
||||
# 普通通知
|
||||
self.notify(title, message, level)
|
||||
|
||||
# 快捷方法
|
||||
self.notify_error(title, message) # 错误通知
|
||||
self.notify_warning(title, message) # 警告通知
|
||||
self.notify_success(title, message) # 成功通知
|
||||
```
|
||||
|
||||
### 配置接收
|
||||
|
||||
在告警配置中添加 Webhook,勾选 **"插件通知"** 事件类型:
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8080/api/v1/webhook/" \
|
||||
-H "X-API-Key: your-api-key" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "插件通知",
|
||||
"url": "https://api.day.app/your-bark-key",
|
||||
"format": "bark",
|
||||
"event_types": ["plugin_notification"]
|
||||
}'
|
||||
```
|
||||
|
||||
### 事件类型
|
||||
|
||||
| 事件类型 | 说明 |
|
||||
|----------|------|
|
||||
| `api_error` | API错误 |
|
||||
| `wechat_offline` | 微信离线 |
|
||||
| `wechat_online` | 微信上线 |
|
||||
| `node_offline` | 节点离线 |
|
||||
| `node_online` | 节点上线 |
|
||||
| `plugin_notification` | 插件通知 |
|
||||
|
||||
---
|
||||
|
||||
## 热加载插件
|
||||
|
||||
### 工作原理
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ HotReloadPluginLoader (独立线程) │
|
||||
│ │
|
||||
│ 1. watchdog 监控 /app/plugins/custom 目录 │
|
||||
│ 2. 检测到 .py 文件变化 → 自动重新加载 │
|
||||
│ 3. importlib 动态导入模块 │
|
||||
│ 4. 自动注册到 PluginRegistry │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 插件目录
|
||||
|
||||
- **Docker 内路径**: `/app/plugins/custom`
|
||||
- **宿主机路径**: `./plugins/custom`
|
||||
|
||||
### 挂载配置
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
volumes:
|
||||
- ./plugins/custom:/app/plugins/custom # 双向同步
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 高级多节点推送插件
|
||||
|
||||
### 简介
|
||||
|
||||
`advanced_sender` 是高级多节点数据推送插件,支持:
|
||||
- 多数据源独立配置
|
||||
- 每数据源独立节点和接收人设置
|
||||
- 外部 MySQL 数据库去重
|
||||
- 班次时段路由
|
||||
- Cookie 失效检测和通知
|
||||
- 熔断保护机制
|
||||
|
||||
### 表单配置
|
||||
|
||||
```
|
||||
默认设置(可被数据源覆盖)
|
||||
├── 默认节点ID: wx1
|
||||
└── 默认接收人: asq
|
||||
|
||||
数据源1
|
||||
├── Cookie: [文本框]
|
||||
├── 节点ID: [留空使用默认]
|
||||
└── 接收人: [留空使用默认]
|
||||
|
||||
数据源2
|
||||
├── Cookie: [文本框]
|
||||
├── 节点ID: [留空使用默认]
|
||||
└── 接收人: [留空使用默认]
|
||||
|
||||
外部数据库
|
||||
├── 数据库地址: 192.168.2.27
|
||||
├── 端口: 3306
|
||||
├── 用户名: root2
|
||||
├── 密码: ****
|
||||
├── 数据库名: addb
|
||||
└── 表名: user_data
|
||||
|
||||
抓取设置
|
||||
├── 请求超时(秒): 15
|
||||
└── 数据源间隔(秒): 20
|
||||
```
|
||||
|
||||
### 配置参数
|
||||
|
||||
| 参数 | 说明 | 默认值 |
|
||||
|------|------|--------|
|
||||
| `cron` | 执行周期 | `*/2 * * * *` |
|
||||
| `enable_cron` | 启用定时任务 | false |
|
||||
| `node_id` | 默认节点ID | wx1 |
|
||||
| `receiver` | 默认接收人 | asq |
|
||||
| `cookie_1` | 数据源1 Cookie | - |
|
||||
| `cookie_2` | 数据源2 Cookie | - |
|
||||
| `node_id_1` | 数据源1节点ID(留空用默认) | - |
|
||||
| `receiver_1` | 数据源1接收人(留空用默认) | - |
|
||||
| `node_id_2` | 数据源2节点ID(留空用默认) | - |
|
||||
| `receiver_2` | 数据源2接收人(留空用默认) | - |
|
||||
| `db_host` | 数据库地址 | 192.168.2.27 |
|
||||
| `db_port` | 端口 | 3306 |
|
||||
| `db_user` | 用户名 | root2 |
|
||||
| `db_password` | 密码 | root@root |
|
||||
| `db_name` | 数据库名 | addb |
|
||||
| `db_table` | 表名 | user_data |
|
||||
| `fetch_timeout` | 请求超时(秒) | 15 |
|
||||
| `send_interval` | 数据源间隔(秒) | 20 |
|
||||
|
||||
### 班次路由
|
||||
|
||||
| 时段 | 路由规则 |
|
||||
|------|----------|
|
||||
| 0-7点 | 跳过 |
|
||||
| 8-16点 | 发送 |
|
||||
| 17-21点 | 发送 |
|
||||
| 22-23点 | 跳过 |
|
||||
|
||||
### 操作
|
||||
|
||||
| action | 说明 |
|
||||
|--------|------|
|
||||
| `send` | 执行完整流程 |
|
||||
| `test` | 测试配置 |
|
||||
| `test_send` | 测试发送(可指定node_id和receiver) |
|
||||
| `query_pending` | 查询待发送数据 |
|
||||
|
||||
### 测试发送
|
||||
|
||||
```bash
|
||||
# 使用默认节点和接收人
|
||||
curl -X POST "http://localhost:8080/api/v1/plugins/advanced_sender/execute" \
|
||||
-H "X-API-Key: your-api-key" \
|
||||
-d '{"action": "test_send", "msg": "测试消息"}'
|
||||
|
||||
# 指定节点和接收人
|
||||
curl -X POST "http://localhost:8080/api/v1/plugins/advanced_sender/execute" \
|
||||
-H "X-API-Key: your-api-key" \
|
||||
-d '{"action": "test_send", "node_id": "wx1", "receiver": "asq", "msg": "测试"}'
|
||||
```
|
||||
|
||||
### 获取日志
|
||||
|
||||
```bash
|
||||
curl "http://localhost:8080/api/v1/plugins/advanced_sender/logs?lines=100" \
|
||||
-H "X-API-Key: your-api-key"
|
||||
```
|
||||
|
||||
### Cookie 失效检测
|
||||
|
||||
- 当 HTTP 返回 403/401 时,判定为 Cookie 失效
|
||||
- 当数据源返回空数据时,判定为 Cookie 可能失效
|
||||
- 首次检测到问题发送告警通知
|
||||
- 恢复成功后发送成功通知
|
||||
- 后续执行不再重复报警
|
||||
|
||||
---
|
||||
|
||||
## 插件管理API
|
||||
|
||||
| 接口 | 方法 | 说明 |
|
||||
|------|------|------|
|
||||
| `GET /api/v1/plugins/` | GET | 获取所有插件 |
|
||||
| `GET /api/v1/plugins/hotloaded` | GET | 获取热加载插件列表 |
|
||||
| `POST /api/v1/plugins/hotreload` | POST | 手动触发热重载 |
|
||||
| `GET /api/v1/plugins/{name}` | GET | 获取插件详情 |
|
||||
| `GET /api/v1/plugins/{name}/schema` | GET | 获取插件表单Schema |
|
||||
| `POST /api/v1/plugins/{name}/enable` | POST | 启用插件 |
|
||||
| `POST /api/v1/plugins/{name}/disable` | POST | 禁用插件 |
|
||||
| `PUT /api/v1/plugins/{name}/config` | PUT | 更新插件配置 |
|
||||
| `POST /api/v1/plugins/{name}/execute` | POST | 执行插件 |
|
||||
| `GET /api/v1/plugins/{name}/logs` | GET | 获取插件日志 |
|
||||
| `POST /api/v1/plugins/{name}/logs/clear` | POST | 清空插件日志 |
|
||||
|
||||
### 配置插件示例
|
||||
|
||||
```bash
|
||||
curl -X PUT "http://localhost:8080/api/v1/plugins/advanced_sender/config" \
|
||||
-H "X-API-Key: your-api-key" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "advanced_sender",
|
||||
"config": {
|
||||
"cron": "*/2 * * * *",
|
||||
"enable_cron": true,
|
||||
"node_id": "wx1",
|
||||
"receiver": "asq",
|
||||
"cookie_1": "PHPSESSID=xxx; think_var=zh-cn",
|
||||
"cookie_2": "PHPSESSID=yyy; think_var=zh-cn",
|
||||
"db_host": "192.168.2.27",
|
||||
"db_port": 3306,
|
||||
"db_user": "root2",
|
||||
"db_password": "root@root",
|
||||
"db_name": "addb",
|
||||
"db_table": "user_data"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
### 执行插件示例
|
||||
|
||||
```bash
|
||||
# 执行发送任务
|
||||
curl -X POST "http://localhost:8080/api/v1/plugins/advanced_sender/execute" \
|
||||
-H "X-API-Key: your-api-key" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"action": "send"}'
|
||||
|
||||
# 测试配置
|
||||
curl -X POST "http://localhost:8080/api/v1/plugins/advanced_sender/execute" \
|
||||
-H "X-API-Key: your-api-key" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"action": "test"}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 前端使用
|
||||
|
||||
访问 **插件管理** 页面(侧边栏菜单):
|
||||
|
||||
1. **查看插件列表** - 显示所有已注册插件
|
||||
2. **启用/禁用** - 点击按钮控制插件状态
|
||||
3. **配置** - 点击配置按钮打开表单化配置界面
|
||||
4. **日志** - 点击日志按钮查看插件独立日志
|
||||
5. **执行** - 点击执行按钮测试插件
|
||||
|
||||
### 配置界面
|
||||
|
||||
- 表单化配置,无需手动编辑 JSON
|
||||
- Section 可折叠,方便管理
|
||||
- 支持所有字段类型(文本、数字、密码、开关、下拉等)
|
||||
- 自动验证必填项
|
||||
|
||||
### 日志界面
|
||||
|
||||
- 实时显示插件日志
|
||||
- 支持刷新
|
||||
- 日志文件保存在 `/app/data/logs/{plugin_name}.log`
|
||||
|
||||
---
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 使用表单化配置
|
||||
|
||||
```python
|
||||
from plugins.plugin_config_schema import (
|
||||
PluginConfigSchema, ConfigSection, ConfigField, FieldType
|
||||
)
|
||||
|
||||
def get_config_schema() -> PluginConfigSchema:
|
||||
schema = PluginConfigSchema("my_plugin")
|
||||
schema.add_section(ConfigSection(
|
||||
name="basic",
|
||||
label="基本设置",
|
||||
fields=[
|
||||
ConfigField(name="key", label="键", field_type=FieldType.STRING, required=True)
|
||||
]
|
||||
))
|
||||
return schema
|
||||
|
||||
class MyPlugin(ScheduledTaskPlugin):
|
||||
config_schema = staticmethod(get_config_schema)
|
||||
```
|
||||
|
||||
### 2. 使用通知功能
|
||||
|
||||
```python
|
||||
class MyPlugin(ScheduledTaskPlugin):
|
||||
def run_task(self):
|
||||
try:
|
||||
# 业务逻辑
|
||||
self.notify_success("任务完成", "发送了 10 条消息")
|
||||
except Exception as e:
|
||||
self.notify_error("任务失败", str(e))
|
||||
```
|
||||
|
||||
### 3. 错误处理
|
||||
|
||||
```python
|
||||
def execute(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
try:
|
||||
return {"success": True, "data": result}
|
||||
except Exception as e:
|
||||
return {"success": False, "error": str(e)}
|
||||
```
|
||||
|
||||
### 4. 定时任务防重复
|
||||
|
||||
```python
|
||||
def run_task(self) -> Dict[str, Any]:
|
||||
if self._running:
|
||||
logger.warning("Previous task still running, skipping")
|
||||
return {"success": False, "error": "上一次执行尚未完成"}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
wxauto_api/
|
||||
├── plugins/
|
||||
│ ├── __init__.py
|
||||
│ ├── base.py # 插件基类和注册表
|
||||
│ ├── builtin.py # 内置插件实现
|
||||
│ ├── plugin_loader.py # 热加载插件加载器
|
||||
│ ├── plugin_config_schema.py # 表单化配置系统
|
||||
│ ├── http_scheduled_sender.py # 定时HTTP推送插件
|
||||
│ ├── advanced_sender_plugin.py # 高级多节点推送插件
|
||||
│ └── custom/ # 自定义插件目录(热加载)
|
||||
│ ├── __init__.py
|
||||
│ └── my_plugin.py
|
||||
├── services/
|
||||
│ └── plugin_notification_service.py # 插件通知服务
|
||||
├── static/
|
||||
│ ├── js/
|
||||
│ │ └── app.js # 前端插件管理
|
||||
│ └── css/
|
||||
│ └── style.css
|
||||
└── doc/
|
||||
└── wxauto_center/
|
||||
└── PLUGIN.md # 本文档
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 生命周期
|
||||
|
||||
1. **注册** - `PluginRegistry.register(plugin)`
|
||||
2. **初始化** - `plugin.initialize(config)`
|
||||
3. **启用** - `plugin.enable()`
|
||||
4. **执行** - `plugin.execute(params)` 或 `plugin.run_task()`
|
||||
5. **禁用** - `plugin.disable()`
|
||||
6. **卸载** - `PluginRegistry.unregister(name)`
|
||||
|
||||
### 热加载流程
|
||||
|
||||
1. **启动** - `HotReloadPluginLoader.start()`
|
||||
2. **扫描** - 扫描 `/app/plugins/custom` 目录
|
||||
3. **监听** - `watchdog` 监控文件变化
|
||||
4. **加载** - `importlib` 动态导入模块
|
||||
5. **注册** - 自动注册到 `PluginRegistry`
|
||||
6. **停止** - `HotReloadPluginLoader.stop()`
|
||||
@@ -0,0 +1,286 @@
|
||||
# WXAuto Center 中控系统
|
||||
|
||||
## 项目简介
|
||||
|
||||
WXAuto Center 是一款基于 FastAPI + PostgreSQL + Redis 构建的多节点微信管理中控系统,为企业级微信自动化运营提供集中管理平台。该系统能够同时管理多个 WXAuto-HTTP-API 节点,实现消息统一发送、节点状态监控、实时日志查看和外部程序接入等功能。
|
||||
|
||||
## 主要功能
|
||||
|
||||
- **多节点微信管理**:支持同时接入多个微信节点,按组分类管理
|
||||
- **节点标识系统**:每个节点拥有唯一的 `node_id`(如 "wx1", "node_001")和显示用的 `name`(如 "微信1", "测试节点")
|
||||
- **消息发送**:支持单发、群发、批量发送、模板消息等多种发送模式
|
||||
- **健康检测机制**:通过 `/api/wechat/initialize` 接口检测微信状态,确保消息发送前微信正常运行
|
||||
- **Webhook 告警**:支持企业微信(wechat)和 Bark 两种格式,节点/微信状态变化时自动通知
|
||||
- **实时日志**:通过 SSE(Server-Sent Events)技术实现日志实时推送,默认保留最近500条
|
||||
- **Redis 消息队列**:支持 Redis 后端的消息队列,用于异步消息处理
|
||||
- **多进程支持**:支持多 worker 部署,适应高并发场景
|
||||
- **外部程序接入**:提供标准 RESTful API,支持外部系统调用
|
||||
- **插件系统**:支持扩展插件,包括数据源、AI 智能体、Webhook触发器等
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 环境要求
|
||||
|
||||
- Python 3.8+
|
||||
- Redis (用于消息队列和多进程场景)
|
||||
- FastAPI
|
||||
- httpx(异步 HTTP 客户端)
|
||||
- uvicorn(ASGI 服务器)
|
||||
- pydantic
|
||||
- pydantic-settings
|
||||
|
||||
### 安装步骤
|
||||
|
||||
```bash
|
||||
# 进入项目目录
|
||||
cd wxauto_center
|
||||
|
||||
# 安装依赖
|
||||
pip install -r requirements.txt
|
||||
|
||||
# 复制配置示例文件
|
||||
cp .env.example .env
|
||||
|
||||
# 编辑 .env 文件,修改必要的配置项
|
||||
```
|
||||
|
||||
### 启动服务
|
||||
|
||||
```bash
|
||||
# 单进程启动(默认)
|
||||
python run.py
|
||||
|
||||
# 多进程启动(需要 Redis)
|
||||
python run.py --workers 4
|
||||
|
||||
# 带参数启动
|
||||
python run.py --host 0.0.0.0 --port 8080 --workers 4
|
||||
|
||||
# 开发模式(支持热重载,单进程)
|
||||
python run.py --reload
|
||||
|
||||
# 调试模式
|
||||
python run.py --debug
|
||||
```
|
||||
|
||||
**替代启动方式**:
|
||||
|
||||
```bash
|
||||
# 使用 uvicorn 直接启动
|
||||
uvicorn main:app --host 0.0.0.0 --port 8080 --reload
|
||||
```
|
||||
|
||||
### 访问地址
|
||||
|
||||
- 主界面:http://localhost:8080/static/index.html
|
||||
- API 文档:http://localhost:8080/docs
|
||||
- ReDoc 文档:http://localhost:8080/redoc
|
||||
|
||||
### 快速使用示例
|
||||
|
||||
#### 1. 添加节点
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/v1/nodes \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-API-Key: your-external-api-key" \
|
||||
-d '{
|
||||
"node_id": "wx1",
|
||||
"name": "微信1",
|
||||
"api_url": "http://192.168.20.18:5000",
|
||||
"api_key": "your-node-api-key",
|
||||
"description": "生产节点",
|
||||
"group": "wechat"
|
||||
}'
|
||||
```
|
||||
|
||||
**节点标识说明**:
|
||||
- `node_id`:节点唯一标识,如 "wx1", "node_001",用于 API 调用
|
||||
- `name`:节点显示名称,如 "微信1", "测试节点",用于界面展示
|
||||
|
||||
#### 2. 发送消息
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/v1/messages/send \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-API-Key: your-external-api-key" \
|
||||
-d '{
|
||||
"node_id": "wx1",
|
||||
"who": "wxid_friend",
|
||||
"msg": "您好,这是一条测试消息",
|
||||
"msg_type": "text"
|
||||
}'
|
||||
```
|
||||
|
||||
#### 3. 查询节点状态
|
||||
|
||||
```bash
|
||||
curl http://localhost:8080/api/v1/nodes/wx1/status \
|
||||
-H "X-API-Key: your-external-api-key"
|
||||
```
|
||||
|
||||
#### 4. 重置微信状态(当微信掉线时)
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/v1/callback/node/reset \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-API-Key: your-external-api-key" \
|
||||
-d '{
|
||||
"node_id": "wx1"
|
||||
}'
|
||||
```
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
wxauto_api/
|
||||
├── main.py # FastAPI 主入口
|
||||
├── run.py # 启动脚本
|
||||
├── config.py # 配置管理
|
||||
├── config.json # 应用配置(不含节点和 Webhook)
|
||||
├── .env # Docker 环境变量配置
|
||||
├── models.py # 数据模型(Node, LogEntry, WebhookUrl)
|
||||
├── database_service.py # 数据库服务
|
||||
├── api/ # API 路由模块
|
||||
│ ├── __init__.py
|
||||
│ ├── nodes.py # 节点管理 API
|
||||
│ ├── messages.py # 消息发送 API
|
||||
│ ├── external.py # 外部扩展接口
|
||||
│ ├── callback.py # 回调接口
|
||||
│ ├── plugins.py # 插件管理 API
|
||||
│ └── webhook.py # Webhook 管理 API
|
||||
├── services/ # 业务逻辑服务
|
||||
│ ├── node_manager.py # 节点管理器
|
||||
│ ├── monitor_service.py # 监控服务
|
||||
│ └── log_service.py # 日志服务
|
||||
├── plugins/ # 插件系统
|
||||
│ ├── base.py # 插件基类
|
||||
│ └── builtin.py # 内置插件
|
||||
├── static/ # Web 静态资源
|
||||
│ ├── index.html # 主页面
|
||||
│ ├── css/style.css # 样式表
|
||||
│ └── js/ # JavaScript 模块
|
||||
├── scripts/ # 脚本目录
|
||||
│ ├── start_amd64.sh # amd64 启动脚本
|
||||
│ ├── start_arm64.sh # arm64 启动脚本
|
||||
│ └── database/ # 数据库脚本
|
||||
├── doc/ # 文档目录
|
||||
│ └── wxauto_center/ # 项目文档
|
||||
├── data/ # 数据目录
|
||||
│ ├── db/ # PostgreSQL 数据
|
||||
│ ├── redis/ # Redis 数据
|
||||
│ └── logs/ # 应用日志
|
||||
├── docker-compose.yml # Docker Compose 配置
|
||||
└── Dockerfile # Docker 构建文件
|
||||
```
|
||||
|
||||
## 配置说明
|
||||
|
||||
系统配置支持多种配置源,按优先级从高到低依次为:
|
||||
1. 环境变量(`.env` 文件)
|
||||
2. 配置文件(`config.json`)
|
||||
3. 代码默认值
|
||||
|
||||
### 配置文件
|
||||
|
||||
**config.json** - 应用配置(不含节点和 Webhook):
|
||||
|
||||
```json
|
||||
{
|
||||
"app_name": "WXAuto Center",
|
||||
"host": "0.0.0.0",
|
||||
"port": 8080,
|
||||
"debug": true,
|
||||
"secret_key": "wxauto-center-secret-key-change-in-production",
|
||||
"workers": 1,
|
||||
"cors_origins": ["*"],
|
||||
"api_prefix": "/api/v1",
|
||||
"external_api_key": "your-external-api-key",
|
||||
"monitor": {
|
||||
"enabled": true,
|
||||
"check_interval": 30
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**.env** - Docker 环境变量配置:
|
||||
|
||||
```
|
||||
DATABASE_URL=postgresql://wxauto:wxauto_password@postgres:5432/wxauto
|
||||
REDIS_URL=redis://redis:6379/0
|
||||
APP_NAME=WXAuto Center
|
||||
HOST=0.0.0.0
|
||||
PORT=8080
|
||||
DEBUG=true
|
||||
SECRET_KEY=wxauto-center-secret-key-change-in-production
|
||||
WORKERS=1
|
||||
API_PREFIX=/api/v1
|
||||
EXTERNAL_API_KEY=your-external-api-key
|
||||
CORS_ORIGINS=["*"]
|
||||
MONITOR_ENABLED=true
|
||||
MONITOR_CHECK_INTERVAL=30
|
||||
```
|
||||
|
||||
### 节点配置
|
||||
|
||||
节点配置存储在 PostgreSQL 的 `nodes` 表中,运行时从数据库加载。详细说明请参阅 [CONFIG.md](./CONFIG.md)。
|
||||
|
||||
### Webhook 配置
|
||||
|
||||
Webhook 配置存储在 PostgreSQL 的 `webhook_urls` 表中,支持企业微信和 Bark 两种格式。详细说明请参阅 [CONFIG.md](./CONFIG.md)。
|
||||
|
||||
## API 文档
|
||||
|
||||
系统提供完整的 RESTful API,包括:
|
||||
|
||||
- **节点管理**:`/api/v1/nodes` - 节点的添加、删除、启用/禁用、状态检测
|
||||
- **消息发送**:`/api/v1/messages` - 单发、群发、批量发送、模板消息
|
||||
- **外部接口**:`/api/v1/external` - 供外部程序调用的接口
|
||||
- **回调接口**:`/api/v1/callback` - 节点状态重置、状态检测
|
||||
- **插件管理**:`/api/v1/plugins` - 插件的注册和调用
|
||||
- **配置管理**:`/api/v1/config/webhook`, `/api/v1/config/monitor` - Webhook和监控配置
|
||||
- **监控状态**:`/api/v1/monitor/status` - 实时监控状态
|
||||
- **日志服务**:`/api/v1/logs/*` - 日志查询和实时推送(SSE)
|
||||
|
||||
详细 API 说明请参阅 [API.md](./API.md)
|
||||
|
||||
## 业务流程
|
||||
|
||||
系统主要业务流程包括消息发送流程、回调重置流程和监控告警流程。详细说明请参阅 [FLOWS.md](./FLOWS.md)。
|
||||
|
||||
## 开发指南
|
||||
|
||||
如需进行二次开发或扩展功能,请参阅 [DEVELOPMENT.md](./DEVELOPMENT.md),其中包含:
|
||||
|
||||
- 开发环境搭建
|
||||
- 代码结构说明
|
||||
- 插件开发指南
|
||||
- API 调用示例
|
||||
|
||||
## 常见问题
|
||||
|
||||
如遇到问题,请参阅 [TROUBLESHOOTING.md](./TROUBLESHOOTING.md)
|
||||
|
||||
## 核心设计理念
|
||||
|
||||
### 1. 节点标识系统
|
||||
|
||||
每个节点有两个标识:
|
||||
- `node_id`:节点唯一标识符,用于 API 调用和系统内部引用,示例:"wx1", "node_001"
|
||||
- `name`:节点显示名称,用于界面展示和用户友好提示,示例:"微信1", "测试节点"
|
||||
|
||||
### 2. 健康检测机制
|
||||
|
||||
每次发送消息前,系统会自动调用 `/api/wechat/initialize` 接口初始化微信,确保微信处于可发送消息的状态。这是官方推荐的正确流程。
|
||||
|
||||
### 3. 监控告警
|
||||
|
||||
监控服务定时检测所有节点和微信状态,当状态发生变化时自动触发Webhook通知。支持的事件类型包括:api_error、wechat_offline、wechat_online、node_offline、node_online。
|
||||
|
||||
### 4. 日志服务
|
||||
|
||||
采用内存存储+发布订阅模式,支持SSE实时推送。默认保留最近500条日志,足够应对日常调试和监控需求。
|
||||
|
||||
## 许可证
|
||||
|
||||
本项目仅供学习交流使用,请勿用于违规用途。
|
||||
@@ -0,0 +1,619 @@
|
||||
# WXAuto Center 常见问题与解决方案
|
||||
|
||||
## 概述
|
||||
|
||||
本文档收集了 WXAuto Center 使用过程中可能遇到的常见问题及其解决方案。
|
||||
|
||||
---
|
||||
|
||||
## 1. 服务启动问题
|
||||
|
||||
### 1.1 端口被占用
|
||||
|
||||
**问题描述**:
|
||||
|
||||
```
|
||||
Error: [Errno 48] Address already in use
|
||||
```
|
||||
|
||||
**可能原因**:
|
||||
- 另一个进程正在使用 8080 端口
|
||||
- 上一次启动的服务未正常关闭
|
||||
|
||||
**解决方案**:
|
||||
|
||||
```bash
|
||||
# 查找占用端口的进程
|
||||
lsof -i :8080 # macOS
|
||||
# 或
|
||||
netstat -tlnp | grep 8080 # Linux
|
||||
|
||||
# 终止占用进程
|
||||
kill -9 <PID>
|
||||
|
||||
# 或使用其他端口启动
|
||||
# 修改 config.json 中 port 为其他值,如 8081
|
||||
```
|
||||
|
||||
### 1.2 依赖库安装失败
|
||||
|
||||
**问题描述**:
|
||||
|
||||
```
|
||||
ModuleNotFoundError: No module named 'fastapi'
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
```bash
|
||||
# 确保使用 Python 3.8+
|
||||
python --version
|
||||
|
||||
# 升级 pip
|
||||
pip install --upgrade pip
|
||||
|
||||
# 重新安装依赖
|
||||
pip install -r requirements.txt
|
||||
|
||||
# 或使用国内镜像
|
||||
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
```
|
||||
|
||||
### 1.3 配置文件格式错误
|
||||
|
||||
**问题描述**:
|
||||
|
||||
```
|
||||
JSONDecodeError: Expecting property name enclosed in double quotes
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
检查 `config.json` 文件是否为有效的 JSON 格式:
|
||||
|
||||
```bash
|
||||
# 验证 JSON 格式
|
||||
python -c "import json; json.load(open('config.json'))"
|
||||
|
||||
# 或使用在线 JSON 验证工具
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. API 认证问题
|
||||
|
||||
### 2.1 API Key 无效
|
||||
|
||||
**问题描述**:
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": "Invalid API Key"
|
||||
}
|
||||
```
|
||||
|
||||
**可能原因**:
|
||||
- 请求时未提供 `X-API-Key` Header
|
||||
- 提供的 API Key 与配置不匹配
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 确认在请求头中添加了正确的 Header:
|
||||
|
||||
```bash
|
||||
curl -H "X-API-Key: your-external-api-key" http://localhost:8080/api/v1/nodes
|
||||
```
|
||||
|
||||
2. 检查 `config.json` 或 `.env` 中的 `external_api_key` 配置:
|
||||
|
||||
```json
|
||||
{
|
||||
"external_api_key": "your-external-api-key"
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 CORS 跨域问题
|
||||
|
||||
**问题描述**:
|
||||
|
||||
```
|
||||
Access-Control-Allow-Origin' header is present on the requested resource
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 在 `config.json` 中配置允许的来源:
|
||||
|
||||
```json
|
||||
{
|
||||
"cors_origins": ["http://localhost:3000", "https://your-domain.com"]
|
||||
}
|
||||
```
|
||||
|
||||
2. 或设置 `cors_origins": ["*"]`(仅开发环境)
|
||||
|
||||
---
|
||||
|
||||
## 3. 节点管理问题
|
||||
|
||||
### 3.1 节点添加失败
|
||||
|
||||
**问题描述**:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"error": "Node 'xxx' already exists"
|
||||
}
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
- 节点名称具有唯一性,不能重复
|
||||
- 使用不同的名称添加节点
|
||||
- 或先删除已有节点后再添加
|
||||
|
||||
```bash
|
||||
# 删除节点
|
||||
curl -X DELETE http://localhost:8080/api/v1/nodes/node1 \
|
||||
-H "X-API-Key: your-api-key"
|
||||
```
|
||||
|
||||
### 3.2 节点连接失败
|
||||
|
||||
**问题描述**:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"is_healthy": false,
|
||||
"health_message": "API status: error"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**可能原因**:
|
||||
- 节点服务未启动
|
||||
- API URL 配置错误
|
||||
- 网络不通
|
||||
- API Key 不正确
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 确认节点服务正在运行:
|
||||
|
||||
```bash
|
||||
# 在节点服务器上检查
|
||||
curl http://节点IP:5000/health
|
||||
```
|
||||
|
||||
2. 检查节点配置:
|
||||
|
||||
```bash
|
||||
# 获取节点信息
|
||||
curl http://localhost:8080/api/v1/nodes/node1 \
|
||||
-H "X-API-Key: your-api-key"
|
||||
```
|
||||
|
||||
3. 测试节点 API 连通性:
|
||||
|
||||
```bash
|
||||
# 直接测试节点 API
|
||||
curl -X POST http://节点IP:5000/api/wechat/initialize \
|
||||
-H "X-API-Key: 节点API密钥"
|
||||
```
|
||||
|
||||
### 3.3 节点健康检测失败
|
||||
|
||||
**问题描述**:
|
||||
|
||||
```json
|
||||
{
|
||||
"health_message": "WeChat error: 无效"
|
||||
}
|
||||
```
|
||||
|
||||
**可能原因**:
|
||||
- 微信窗口未打开或已关闭
|
||||
- 微信版本不兼容
|
||||
- WXAuto-HTTP-API 服务异常
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 在对应节点上手动初始化微信:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/v1/nodes/node1/wechat/initialize \
|
||||
-H "X-API-Key: your-api-key"
|
||||
```
|
||||
|
||||
2. 检查节点服务器的微信客户端是否正常运行
|
||||
|
||||
3. 重启节点服务
|
||||
|
||||
---
|
||||
|
||||
## 4. 消息发送问题
|
||||
|
||||
### 4.1 消息发送失败 - 节点不健康
|
||||
|
||||
**问题描述**:
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": "Node 'node1' is not healthy: WeChat check failed. Message sending failed."
|
||||
}
|
||||
```
|
||||
|
||||
**HTTP 状态码**:503
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 先检查节点状态:
|
||||
|
||||
```bash
|
||||
curl http://localhost:8080/api/v1/nodes/node1/status \
|
||||
-H "X-API-Key: your-api-key"
|
||||
```
|
||||
|
||||
2. 确保微信客户端在节点机器上正常运行
|
||||
|
||||
3. 手动初始化微信:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/v1/nodes/node1/wechat/initialize \
|
||||
-H "X-API-Key: your-api-key"
|
||||
```
|
||||
|
||||
### 4.2 消息发送失败 - 接收者不存在
|
||||
|
||||
**问题描述**:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"code": 1,
|
||||
"message": "receiver not found"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 确认接收者的 wxid 或群ID 是否正确
|
||||
2. 获取好友/群列表确认:
|
||||
|
||||
```bash
|
||||
# 获取好友列表
|
||||
curl http://localhost:8080/api/v1/nodes/node1/friends \
|
||||
-H "X-API-Key: your-api-key"
|
||||
|
||||
# 获取群列表
|
||||
curl http://localhost:8080/api/v1/nodes/node1/groups \
|
||||
-H "X-API-Key: your-api-key"
|
||||
```
|
||||
|
||||
### 4.3 消息类型不支持
|
||||
|
||||
**问题描述**:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"code": 1,
|
||||
"message": "unsupported message type"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
目前系统仅支持 `text` 类型消息,消息发送时指定 `msg_type`:
|
||||
|
||||
```json
|
||||
{
|
||||
"node_id": "wx1",
|
||||
"who": "wxid_friend",
|
||||
"msg": "Hello!",
|
||||
"msg_type": "text"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Webhook 问题
|
||||
|
||||
### 5.1 Webhook 通知发送失败
|
||||
|
||||
**问题描述**:
|
||||
|
||||
日志中出现 `Webhook通知发送失败` 相关信息。
|
||||
|
||||
**可能原因**:
|
||||
- Webhook URL 配置错误
|
||||
- 网络不通
|
||||
- Webhook 服务不可用
|
||||
- 消息格式不被接受
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 检查 Webhook 配置:
|
||||
|
||||
```bash
|
||||
curl http://localhost:8080/api/v1/config/webhook \
|
||||
-H "X-API-Key: your-api-key"
|
||||
```
|
||||
|
||||
2. 测试 Webhook URL 是否可用:
|
||||
|
||||
```bash
|
||||
# 测试企业微信 Webhook
|
||||
curl -X POST "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=your-key" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"msgtype": "text", "text": {"content": "test"}}'
|
||||
```
|
||||
|
||||
3. 检查 Webhook 事件类型配置:
|
||||
|
||||
```json
|
||||
{
|
||||
"event_types": ["api_error", "wechat_offline", "wechat_online", "node_offline", "node_online"]
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 Bark 通知格式问题
|
||||
|
||||
**问题描述**:
|
||||
|
||||
Bark 格式的 Webhook 发送失败。
|
||||
|
||||
**解决方案**:
|
||||
|
||||
确保 Webhook URL 正确,格式为:`https://api.day.app/your-bark-id`
|
||||
|
||||
---
|
||||
|
||||
## 6. 监控服务问题
|
||||
|
||||
### 6.1 监控服务未启动
|
||||
|
||||
**问题描述**:
|
||||
|
||||
日志中没有看到监控服务的输出,状态变化不触发 Webhook。
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 检查监控配置:
|
||||
|
||||
```bash
|
||||
curl http://localhost:8080/api/v1/config/monitor \
|
||||
-H "X-API-Key: your-api-key"
|
||||
```
|
||||
|
||||
2. 确保 `enabled` 为 `true`
|
||||
|
||||
3. 检查监控状态:
|
||||
|
||||
```bash
|
||||
curl http://localhost:8080/api/v1/monitor/status \
|
||||
-H "X-API-Key: your-api-key"
|
||||
```
|
||||
|
||||
### 6.2 监控检测间隔过长
|
||||
|
||||
**问题描述**:
|
||||
|
||||
状态变化后很久才收到 Webhook 通知。
|
||||
|
||||
**解决方案**:
|
||||
|
||||
调整 `check_interval` 配置:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/v1/config/monitor \
|
||||
-H "X-API-Key: your-api-key" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"enabled": true,
|
||||
"check_interval": 30
|
||||
}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 日志问题
|
||||
|
||||
### 7.1 SSE 日志流断开
|
||||
|
||||
**问题描述**:
|
||||
|
||||
前端日志流连接经常断开。
|
||||
|
||||
**可能原因**:
|
||||
- 网络问题
|
||||
- 服务器负载过高
|
||||
- 客户端处理不及时
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 检查网络连接
|
||||
2. 实现断线重连机制:
|
||||
|
||||
```javascript
|
||||
function connectLogStream() {
|
||||
const eventSource = new EventSource('/api/v1/logs/stream');
|
||||
|
||||
eventSource.onmessage = (event) => {
|
||||
const log = JSON.parse(event.data);
|
||||
// 处理日志
|
||||
};
|
||||
|
||||
eventSource.onerror = () => {
|
||||
console.log('Connection lost, reconnecting...');
|
||||
setTimeout(connectLogStream, 3000);
|
||||
};
|
||||
|
||||
return eventSource;
|
||||
}
|
||||
```
|
||||
|
||||
### 7.2 日志丢失
|
||||
|
||||
**问题描述**:
|
||||
|
||||
日志数量超过 500 条后,早期的日志被清除。
|
||||
|
||||
**解决方案**:
|
||||
|
||||
这是系统设计行为,`LogService` 默认只保留最近 500 条日志。如需更多日志存储,可以:
|
||||
|
||||
1. 修改 `log_service.py` 中的 `max_logs` 参数
|
||||
2. 实现日志持久化存储(写入文件或数据库)
|
||||
|
||||
---
|
||||
|
||||
## 8. 插件问题
|
||||
|
||||
### 8.1 插件未注册
|
||||
|
||||
**问题描述**:
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": "Plugin 'xxx' not found"
|
||||
}
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 检查插件是否已注册:
|
||||
|
||||
```bash
|
||||
curl http://localhost:8080/api/v1/plugins \
|
||||
-H "X-API-Key: your-api-key"
|
||||
```
|
||||
|
||||
2. 确认内置插件是否在启动时正确注册(检查 `builtin.py`)
|
||||
|
||||
### 8.2 插件执行失败
|
||||
|
||||
**问题描述**:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"error": "Plugin execution failed"
|
||||
}
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 检查插件配置是否正确
|
||||
2. 查看系统日志获取详细错误信息
|
||||
3. 测试插件 API:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/v1/external/plugin/execute \
|
||||
-H "X-API-Key: your-api-key" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"plugin_name": "plugin_name",
|
||||
"action": "execute",
|
||||
"params": {}
|
||||
}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 性能问题
|
||||
|
||||
### 9.1 高并发下响应慢
|
||||
|
||||
**可能原因**:
|
||||
- 节点数量过多
|
||||
- 网络延迟
|
||||
- 同步阻塞操作
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 增加监控检测间隔
|
||||
2. 使用异步调用优化
|
||||
3. 部署多实例负载均衡
|
||||
|
||||
### 9.2 内存占用过高
|
||||
|
||||
**可能原因**:
|
||||
- 日志队列过大
|
||||
- 订阅者过多
|
||||
- 节点对象未及时释放
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 减少 `LogService` 的 `max_logs` 参数
|
||||
2. 及时关闭不需要的 SSE 连接
|
||||
3. 定期重启服务清理内存
|
||||
|
||||
---
|
||||
|
||||
## 10. 安全问题
|
||||
|
||||
### 10.1 API Key 泄露
|
||||
|
||||
**风险**:外部系统可能非法访问 API
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 立即更换 API Key
|
||||
2. 限制 CORS 来源
|
||||
3. 使用 HTTPS 传输
|
||||
4. 定期轮换 API Key
|
||||
|
||||
### 10.2 生产环境安全建议
|
||||
|
||||
1. 修改默认的 `secret_key`
|
||||
2. 设置 `debug: false`
|
||||
3. 配置正确的 `cors_origins`
|
||||
4. 使用强密码的 API Key
|
||||
5. 启用 HTTPS
|
||||
6. 配置防火墙规则
|
||||
|
||||
---
|
||||
|
||||
## 诊断命令汇总
|
||||
|
||||
```bash
|
||||
# 检查服务健康状态
|
||||
curl http://localhost:8080/health
|
||||
|
||||
# 检查监控状态
|
||||
curl http://localhost:8080/api/v1/monitor/status \
|
||||
-H "X-API-Key: your-key"
|
||||
|
||||
# 检查节点状态
|
||||
curl http://localhost:8080/api/v1/nodes \
|
||||
-H "X-API-Key: your-key"
|
||||
|
||||
# 检查 Webhook 配置
|
||||
curl http://localhost:8080/api/v1/config/webhook \
|
||||
-H "X-API-Key: your-key"
|
||||
|
||||
# 检查最近日志
|
||||
curl "http://localhost:8080/api/v1/logs/recent?count=20" \
|
||||
-H "X-API-Key: your-key"
|
||||
|
||||
# 检查插件列表
|
||||
curl http://localhost:8080/api/v1/plugins \
|
||||
-H "X-API-Key: your-key"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 获取帮助
|
||||
|
||||
如果以上方案无法解决您的问题,请:
|
||||
|
||||
1. 查看详细日志输出
|
||||
2. 检查系统环境配置
|
||||
3. 确认网络连通性
|
||||
4. 查看 [API.md](./API.md) 确认 API 使用正确
|
||||
5. 查看 [ARCHITECTURE.md](./ARCHITECTURE.md) 了解系统架构
|
||||
@@ -0,0 +1,271 @@
|
||||
# WXAuto Relogin - API 接口文档
|
||||
|
||||
## 1. 概述
|
||||
|
||||
本文档定义 WXAuto Relogin 功能所需的 API 接口。
|
||||
|
||||
## 2. 回调接口
|
||||
|
||||
### 2.1 接收二维码
|
||||
|
||||
客户端上传二维码到中控。
|
||||
|
||||
```
|
||||
POST /api/v1/callback/relogin/qrcode
|
||||
```
|
||||
|
||||
**Headers:**
|
||||
```
|
||||
X-API-Key: your-api-key
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"node_id": "wx1",
|
||||
"qrcode_base64": "data:image/png;base64,iVBORw0KGgo...",
|
||||
"expires_in": 120
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| node_id | string | 是 | 节点ID |
|
||||
| qrcode_base64 | string | 是 | Base64编码的PNG图片,带data URI前缀 |
|
||||
| expires_in | integer | 否 | 过期时间(秒),默认120 |
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "二维码已接收",
|
||||
"data": {
|
||||
"status": "qrcode_ready",
|
||||
"expires_at": "2026-04-07T15:30:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 更新重登录状态
|
||||
|
||||
```
|
||||
POST /api/v1/callback/relogin/status
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"node_id": "wx1",
|
||||
"status": "scanned",
|
||||
"message": "用户已扫码"
|
||||
}
|
||||
```
|
||||
|
||||
| 状态 | 说明 |
|
||||
|------|------|
|
||||
| waiting_qrcode | 等待获取二维码 |
|
||||
| qrcode_ready | 二维码已就绪 |
|
||||
| scanned | 已扫码,待确认 |
|
||||
| confirmed | 已确认,登录中 |
|
||||
| completed | 登录完成 |
|
||||
| failed | 登录失败 |
|
||||
|
||||
## 3. 节点接口
|
||||
|
||||
### 3.1 获取重登录状态
|
||||
|
||||
```
|
||||
GET /api/v1/nodes/{node_id}/relogin/status
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"node_id": "wx1",
|
||||
"status": "qrcode_ready",
|
||||
"qrcode_base64": "data:image/png;base64,...",
|
||||
"qrcode_expires_at": "2026-04-07T15:30:00",
|
||||
"created_at": "2026-04-07T15:00:00",
|
||||
"updated_at": "2026-04-07T15:05:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 清除重登录状态
|
||||
|
||||
```
|
||||
DELETE /api/v1/nodes/{node_id}/relogin/status
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "状态已清除"
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 客户端管理接口
|
||||
|
||||
### 4.1 注册客户端
|
||||
|
||||
```
|
||||
POST /api/v1/relogin/clients
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"client_name": "服务器1",
|
||||
"webhook_url": "http://192.168.1.100:8081/webhook/relogin",
|
||||
"secret_key": "optional_secret_for_signing"
|
||||
}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"id": 1,
|
||||
"client_name": "服务器1",
|
||||
"webhook_url": "http://192.168.1.100:8081/webhook/relogin",
|
||||
"enabled": true,
|
||||
"created_at": "2026-04-07T15:00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 获取客户端列表
|
||||
|
||||
```
|
||||
GET /api/v1/relogin/clients
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": [
|
||||
{
|
||||
"id": 1,
|
||||
"client_name": "服务器1",
|
||||
"webhook_url": "http://192.168.1.100:8081/webhook/relogin",
|
||||
"enabled": true,
|
||||
"created_at": "2026-04-07T15:00:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 更新客户端
|
||||
|
||||
```
|
||||
PUT /api/v1/relogin/clients/{client_id}
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"enabled": false
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 删除客户端
|
||||
|
||||
```
|
||||
DELETE /api/v1/relogin/clients/{client_id}
|
||||
```
|
||||
|
||||
## 5. Webhook 告警格式
|
||||
|
||||
中控向客户端发送的告警格式:
|
||||
|
||||
```json
|
||||
{
|
||||
"event": "wechat_offline",
|
||||
"node_id": "wx1",
|
||||
"node_name": "微信1",
|
||||
"wechat_status": "offline",
|
||||
"timestamp": "2026-04-07T15:00:00",
|
||||
"message": "节点 wx1 微信掉线"
|
||||
}
|
||||
```
|
||||
|
||||
**event 类型:**
|
||||
| 事件 | 说明 |
|
||||
|------|------|
|
||||
| wechat_offline | 微信掉线 |
|
||||
| wechat_online | 微信上线 |
|
||||
| node_offline | 节点离线 |
|
||||
| node_online | 节点上线 |
|
||||
|
||||
## 6. 签名验证(可选)
|
||||
|
||||
如果配置了 secret_key,客户端应验证请求签名:
|
||||
|
||||
```
|
||||
X-Signature: sha256=xxxxxxxxxxxxxx
|
||||
```
|
||||
|
||||
**验证算法:**
|
||||
```python
|
||||
import hmac
|
||||
import hashlib
|
||||
|
||||
def verify_signature(payload: bytes, signature: str, secret: str) -> bool:
|
||||
expected = hmac.new(
|
||||
secret.encode(),
|
||||
payload,
|
||||
hashlib.sha256
|
||||
).hexdigest()
|
||||
return hmac.compare_digest(f"sha256={expected}", signature)
|
||||
```
|
||||
|
||||
## 7. 错误码
|
||||
|
||||
| 错误码 | 说明 |
|
||||
|--------|------|
|
||||
| 404 | 节点不存在 |
|
||||
| 400 | 参数错误 |
|
||||
| 401 | API Key无效 |
|
||||
| 403 | 无权限 |
|
||||
| 500 | 服务器内部错误 |
|
||||
|
||||
## 8. 使用示例
|
||||
|
||||
### 8.1 完整重登录流程
|
||||
|
||||
```bash
|
||||
# 1. 微信掉线,中控发送告警到客户端
|
||||
# 客户端接收: POST /webhook/relogin
|
||||
|
||||
# 2. 客户端从节点获取二维码
|
||||
curl -o qrcode.png http://node-api:5000/api/wechat/qrcode \
|
||||
-H "X-API-Key: node-api-key"
|
||||
|
||||
# 3. 客户端上传二维码到中控
|
||||
curl -X POST http://center:8080/api/v1/callback/relogin/qrcode \
|
||||
-H "X-API-Key: your-api-key" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"node_id": "wx1",
|
||||
"qrcode_base64": "data:image/png;base64,...",
|
||||
"expires_in": 120
|
||||
}'
|
||||
|
||||
# 4. 前端轮询获取状态
|
||||
curl http://center:8080/api/v1/nodes/wx1/relogin/status \
|
||||
-H "X-API-Key: your-api-key"
|
||||
|
||||
# 5. 用户扫码确认后,节点回调通知中控
|
||||
curl -X POST http://center:8080/api/v1/callback/node/check \
|
||||
-d '{"node_id": "wx1", "status": "online"}'
|
||||
|
||||
# 6. 客户端轮询发现 completed
|
||||
curl http://center:8080/api/v1/nodes/wx1/relogin/status
|
||||
# 返回: {"status": "completed"}
|
||||
```
|
||||
@@ -0,0 +1,375 @@
|
||||
# WXAuto Relogin - 客户端开发指南
|
||||
|
||||
## 1. 概述
|
||||
|
||||
本文档说明如何开发 WXAuto Relogin 客户端程序,用于接收中控告警并自动处理微信重登录。
|
||||
|
||||
## 2. 技术栈
|
||||
|
||||
- Python 3.11+
|
||||
- FastAPI (Webhook服务)
|
||||
- httpx (HTTP客户端)
|
||||
- asyncio (异步处理)
|
||||
|
||||
## 3. 项目结构
|
||||
|
||||
```
|
||||
wxauto-relogin-client/
|
||||
├── client/
|
||||
│ ├── __init__.py
|
||||
│ ├── webhook_server.py # Webhook接收服务
|
||||
│ ├── qrcode_handler.py # 二维码处理
|
||||
│ ├── node_client.py # 节点通信
|
||||
│ └── config.py # 配置
|
||||
├── requirements.txt
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## 4. 配置
|
||||
|
||||
```python
|
||||
# client/config.py
|
||||
from pydantic import BaseModel
|
||||
|
||||
class ClientConfig(BaseModel):
|
||||
center_url: str = "http://localhost:8080"
|
||||
center_api_key: str = "your-external-api-key"
|
||||
client_name: str = "relogin-client-1"
|
||||
secret_key: str = "" # 可选,用于签名验证
|
||||
listen_host: str = "0.0.0.0"
|
||||
listen_port: int = 8081
|
||||
|
||||
config = ClientConfig()
|
||||
```
|
||||
|
||||
## 5. Webhook 接收服务
|
||||
|
||||
```python
|
||||
# client/webhook_server.py
|
||||
from fastapi import FastAPI, HTTPException, Header
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from .qrcode_handler import QRCodeHandler
|
||||
from .config import config
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger("relogin-client")
|
||||
|
||||
app = FastAPI()
|
||||
qrcode_handler = QRCodeHandler()
|
||||
|
||||
class ReloginAlert(BaseModel):
|
||||
event: str
|
||||
node_id: str
|
||||
node_name: str
|
||||
wechat_status: str
|
||||
timestamp: str
|
||||
|
||||
@app.post("/webhook/relogin")
|
||||
async def receive_alert(
|
||||
alert: ReloginAlert,
|
||||
x_signature: Optional[str] = Header(None)
|
||||
):
|
||||
"""
|
||||
接收中控的掉线告警
|
||||
"""
|
||||
logger.info(f"Received alert: {alert.node_id} - {alert.wechat_status}")
|
||||
|
||||
# 验证签名(如果配置了secret_key)
|
||||
if config.secret_key:
|
||||
# TODO: 实现签名验证
|
||||
pass
|
||||
|
||||
# 触发重登录流程
|
||||
asyncio.create_task(handle_relogin(alert))
|
||||
|
||||
return {"status": "accepted", "node_id": alert.node_id}
|
||||
|
||||
async def handle_relogin(alert: ReloginAlert):
|
||||
"""
|
||||
处理重登录流程
|
||||
"""
|
||||
try:
|
||||
logger.info(f"Starting relogin for {alert.node_id}")
|
||||
|
||||
# 1. 获取二维码
|
||||
qrcode_base64 = await qrcode_handler.get_and_upload_qrcode(alert.node_id)
|
||||
if qrcode_base64:
|
||||
logger.info(f"QR code uploaded for {alert.node_id}")
|
||||
|
||||
# 2. 等待扫码确认
|
||||
success = await qrcode_handler.wait_for_scan(alert.node_id, timeout=180)
|
||||
if success:
|
||||
logger.info(f"ReLogin successful for {alert.node_id}")
|
||||
else:
|
||||
logger.warning(f"ReLogin timeout for {alert.node_id}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"ReLogin failed for {alert.node_id}: {e}")
|
||||
|
||||
@app.get("/health")
|
||||
async def health():
|
||||
return {"status": "healthy"}
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run(app, host=config.listen_host, port=config.listen_port)
|
||||
```
|
||||
|
||||
## 6. 二维码处理
|
||||
|
||||
```python
|
||||
# client/qrcode_handler.py
|
||||
import httpx
|
||||
import asyncio
|
||||
import time
|
||||
import base64
|
||||
from typing import Optional
|
||||
|
||||
from .config import config
|
||||
|
||||
class QRCodeHandler:
|
||||
def __init__(self):
|
||||
self.center_url = config.center_url
|
||||
self.api_key = config.center_api_key
|
||||
|
||||
async def get_qrcode_from_node(self, api_url: str, node_api_key: str) -> Optional[bytes]:
|
||||
"""
|
||||
从wxauto节点获取二维码
|
||||
"""
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=30.0) as client:
|
||||
response = await client.get(
|
||||
f"{api_url}/api/wechat/qrcode",
|
||||
headers={"X-API-Key": node_api_key}
|
||||
)
|
||||
if response.status_code == 200:
|
||||
return response.content
|
||||
else:
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Failed to get QR code from node: {e}")
|
||||
return None
|
||||
|
||||
async def upload_qrcode_to_center(self, node_id: str, qrcode_bytes: bytes, expires_in: int = 120):
|
||||
"""
|
||||
上传二维码到中控
|
||||
"""
|
||||
qrcode_base64 = base64.b64encode(qrcode_bytes).decode()
|
||||
|
||||
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||
response = await client.post(
|
||||
f"{self.center_url}/api/v1/callback/relogin/qrcode",
|
||||
headers={"X-API-Key": self.api_key},
|
||||
json={
|
||||
"node_id": node_id,
|
||||
"qrcode_base64": f"data:image/png;base64,{qrcode_base64}",
|
||||
"expires_in": expires_in
|
||||
}
|
||||
)
|
||||
return response.json().get("success", False)
|
||||
|
||||
async def get_node_info(self, node_id: str) -> Optional[dict]:
|
||||
"""
|
||||
从中控获取节点信息(包含API地址和密钥)
|
||||
"""
|
||||
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||
response = await client.get(
|
||||
f"{self.center_url}/api/v1/nodes/{node_id}",
|
||||
headers={"X-API-Key": self.api_key}
|
||||
)
|
||||
if response.status_code == 200:
|
||||
return response.json().get("data")
|
||||
return None
|
||||
|
||||
async def get_and_upload_qrcode(self, node_id: str) -> Optional[str]:
|
||||
"""
|
||||
获取二维码并上传到中控
|
||||
"""
|
||||
# 1. 获取节点信息
|
||||
node_info = await self.get_node_info(node_id)
|
||||
if not node_info:
|
||||
print(f"Node {node_id} not found")
|
||||
return None
|
||||
|
||||
# 2. 获取二维码
|
||||
qrcode_bytes = await self.get_qrcode_from_node(
|
||||
api_url=node_info["api_url"],
|
||||
node_api_key=node_info["api_key"]
|
||||
)
|
||||
if not qrcode_bytes:
|
||||
print(f"Failed to get QR code for {node_id}")
|
||||
return None
|
||||
|
||||
# 3. 上传到中控
|
||||
success = await self.upload_qrcode_to_center(node_id, qrcode_bytes)
|
||||
if success:
|
||||
return f"data:image/png;base64,{base64.b64encode(qrcode_bytes).decode()}"
|
||||
return None
|
||||
|
||||
async def wait_for_scan(self, node_id: str, timeout: int = 180) -> bool:
|
||||
"""
|
||||
轮询中控,等待扫码确认
|
||||
"""
|
||||
start_time = time.time()
|
||||
interval = 2 # 每2秒轮询一次
|
||||
|
||||
while time.time() - start_time < timeout:
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||
response = await client.get(
|
||||
f"{self.center_url}/api/v1/nodes/{node_id}/relogin/status",
|
||||
headers={"X-API-Key": self.api_key}
|
||||
)
|
||||
if response.status_code == 200:
|
||||
data = response.json().get("data", {})
|
||||
status = data.get("status")
|
||||
|
||||
print(f"Status: {status}")
|
||||
|
||||
if status == "completed":
|
||||
return True
|
||||
elif status == "failed":
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"Polling error: {e}")
|
||||
|
||||
await asyncio.sleep(interval)
|
||||
|
||||
return False
|
||||
```
|
||||
|
||||
## 7. 节点通信客户端
|
||||
|
||||
```python
|
||||
# client/node_client.py
|
||||
import httpx
|
||||
from typing import Optional
|
||||
|
||||
class NodeClient:
|
||||
def __init__(self, api_url: str, api_key: str):
|
||||
self.api_url = api_url.rstrip("/")
|
||||
self.api_key = api_key
|
||||
|
||||
async def get_qrcode(self) -> Optional[bytes]:
|
||||
"""
|
||||
获取登录二维码
|
||||
"""
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=30.0) as client:
|
||||
response = await client.get(
|
||||
f"{self.api_url}/api/wechat/qrcode",
|
||||
headers={"X-API-Key": self.api_key}
|
||||
)
|
||||
if response.status_code == 200:
|
||||
return response.content
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Failed to get QR code: {e}")
|
||||
return None
|
||||
|
||||
async def check_login_status(self) -> dict:
|
||||
"""
|
||||
检查登录状态
|
||||
"""
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||
response = await client.get(
|
||||
f"{self.api_url}/api/wechat/status",
|
||||
headers={"X-API-Key": self.api_key}
|
||||
)
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
return {"logged_in": False}
|
||||
except Exception as e:
|
||||
return {"logged_in": False, "error": str(e)}
|
||||
|
||||
async def logout(self) -> bool:
|
||||
"""
|
||||
登出微信
|
||||
"""
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||
response = await client.post(
|
||||
f"{self.api_url}/api/wechat/logout",
|
||||
headers={"X-API-Key": self.api_key}
|
||||
)
|
||||
return response.status_code == 200
|
||||
except Exception as e:
|
||||
print(f"Logout failed: {e}")
|
||||
return False
|
||||
```
|
||||
|
||||
## 8. 依赖
|
||||
|
||||
```txt
|
||||
# requirements.txt
|
||||
fastapi>=0.100.0
|
||||
uvicorn>=0.23.0
|
||||
httpx>=0.24.0
|
||||
pydantic>=2.0.0
|
||||
python-dotenv>=1.0.0
|
||||
```
|
||||
|
||||
## 9. 运行
|
||||
|
||||
```bash
|
||||
# 安装依赖
|
||||
pip install -r requirements.txt
|
||||
|
||||
# 运行客户端
|
||||
python -m client.webhook_server
|
||||
```
|
||||
|
||||
## 10. Docker 部署
|
||||
|
||||
```dockerfile
|
||||
# Dockerfile
|
||||
FROM python:3.11-slim
|
||||
|
||||
WORKDIR /app
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY client/ ./client/
|
||||
|
||||
CMD ["python", "-m", "client.webhook_server"]
|
||||
```
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
relogin-client:
|
||||
build: .
|
||||
ports:
|
||||
- "8081:8081"
|
||||
environment:
|
||||
- CENTER_URL=http://your-center:8080
|
||||
- CENTER_API_KEY=your-api-key
|
||||
- CLIENT_NAME=relogin-1
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
## 11. 完整示例
|
||||
|
||||
```python
|
||||
# main.py
|
||||
import asyncio
|
||||
from client.webhook_server import app
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run(app, host="0.0.0.0", port=8081)
|
||||
```
|
||||
|
||||
## 12. 注意事项
|
||||
|
||||
1. **网络安全**: 确保客户端Webhook端口能从公网访问
|
||||
2. **签名验证**: 生产环境建议启用signature验证
|
||||
3. **超时设置**: 二维码有效期通常120秒,需要及时处理
|
||||
4. **重试机制**: 建议添加失败重试逻辑
|
||||
5. **日志记录**: 保留完整日志便于排查问题
|
||||
@@ -0,0 +1,400 @@
|
||||
# WXAuto Relogin - 微信自动重登录方案
|
||||
|
||||
## 1. 背景问题
|
||||
|
||||
### 1.1 当前痛点
|
||||
- 微信掉线后,需要人工介入扫码登录
|
||||
- 节点多时,人工操作繁琐
|
||||
- 无法远程自动恢复微信会话
|
||||
|
||||
### 1.2 现有架构
|
||||
```
|
||||
中控(Center) ←→ 节点(Node)
|
||||
↑
|
||||
API通信/回调
|
||||
```
|
||||
|
||||
## 2. 解决方案概述
|
||||
|
||||
### 2.1 核心理念
|
||||
```
|
||||
微信掉线 → 中控告警 → 客户端接收 → 获取二维码 → 回传中控 → 前端展示扫码
|
||||
```
|
||||
|
||||
### 2.2 系统架构
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ WXAuto Center │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ 告警系统 │→ │ 插件系统 │← │ 前端展示 │ │
|
||||
│ │ (Webhook) │ │(wxautorelogin)│ │ (二维码) │ │
|
||||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||||
│ ↑ │ │
|
||||
│ │ ┌──────────────┐ │ │
|
||||
│ └─────────│ 回调接口 │───────────┘ │
|
||||
│ │ /callback │ │
|
||||
│ └──────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↑ HTTP
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ WXAuto Relogin Client │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ 消息接收 │ │ 二维码获取 │→ │ 状态回调 │ │
|
||||
│ │ (Webhook) │ │(get QR code) │ │ (重置微信) │ │
|
||||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 3. 实现方案
|
||||
|
||||
### 3.1 中控端改动
|
||||
|
||||
#### 3.1.1 新增 API 接口
|
||||
|
||||
| 接口 | 方法 | 说明 |
|
||||
|------|------|------|
|
||||
| `POST /api/v1/callback/relogin/qrcode` | 接收二维码 | 客户端回传二维码图片 |
|
||||
| `GET /api/v1/nodes/{node_id}/relogin/status` | 重登录状态 | 查询节点重登录进度 |
|
||||
|
||||
#### 3.1.2 二维码存储结构
|
||||
|
||||
```python
|
||||
# NodeReloginStatus
|
||||
{
|
||||
"node_id": "wx1",
|
||||
"status": "waiting_qrcode" | "qrcode_ready" | "scanned" | "confirmed" | "completed" | "failed",
|
||||
"qrcode_base64": "data:image/png;base64,...",
|
||||
"qrcode_expires_at": "2026-04-07T15:30:00",
|
||||
"created_at": "2026-04-07T15:00:00",
|
||||
"updated_at": "2026-04-07T15:05:00"
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.1.3 前端展示
|
||||
|
||||
- 节点详情页增加"重登录"标签页
|
||||
- 实时显示二维码(轮询 /api/v1/nodes/{node_id}/relogin/status)
|
||||
- 二维码过期提示
|
||||
|
||||
### 3.2 客户端改动
|
||||
|
||||
#### 3.2.1 Webhook 接收器
|
||||
|
||||
客户端需要暴露一个 HTTP 接口接收中控告警:
|
||||
|
||||
```python
|
||||
# client/webhook_server.py
|
||||
from fastapi import FastAPI
|
||||
import uvicorn
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@app.post("/webhook/relogin")
|
||||
async def receive_alert(data: dict):
|
||||
"""
|
||||
接收中控的掉线告警
|
||||
{
|
||||
"event": "wechat_offline",
|
||||
"node_id": "wx1",
|
||||
"node_name": "微信1",
|
||||
"wechat_status": "offline",
|
||||
"timestamp": "2026-04-07T15:00:00"
|
||||
}
|
||||
"""
|
||||
# 触发获取二维码流程
|
||||
await trigger_relogin(node_id=data["node_id"])
|
||||
return {"status": "ok"}
|
||||
|
||||
async def trigger_relogin(node_id: str):
|
||||
# 1. 调用节点API获取二维码
|
||||
# 2. 上传二维码到中控
|
||||
# 3. 等待扫码确认
|
||||
pass
|
||||
```
|
||||
|
||||
#### 3.2.2 二维码获取流程
|
||||
|
||||
```python
|
||||
async def get_qrcode_from_node(api_url: str, api_key: str) -> bytes:
|
||||
"""
|
||||
从wxauto节点获取二维码
|
||||
GET /api/wechat/qrcode
|
||||
返回: PNG图片二进制
|
||||
"""
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.get(
|
||||
f"{api_url}/api/wechat/qrcode",
|
||||
headers={"X-API-Key": api_key}
|
||||
)
|
||||
return response.content
|
||||
|
||||
async def upload_qrcode_to_center(center_url: str, node_id: str, qrcode_bytes: bytes):
|
||||
"""
|
||||
上传二维码到中控
|
||||
POST /api/v1/callback/relogin/qrcode
|
||||
"""
|
||||
async with httpx.AsyncClient() as client:
|
||||
import base64
|
||||
qrcode_base64 = base64.b64encode(qrcode_bytes).decode()
|
||||
await client.post(
|
||||
f"{center_url}/api/v1/callback/relogin/qrcode",
|
||||
json={
|
||||
"node_id": node_id,
|
||||
"qrcode_base64": qrcode_base64
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
#### 3.2.3 扫码状态轮询
|
||||
|
||||
```python
|
||||
async def wait_for_scan(center_url: str, node_id: str, timeout: int = 120):
|
||||
"""
|
||||
轮询中控接口,等待用户扫码确认
|
||||
"""
|
||||
start_time = time.time()
|
||||
while time.time() - start_time < timeout:
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.get(
|
||||
f"{center_url}/api/v1/nodes/{node_id}/relogin/status"
|
||||
)
|
||||
status = response.json()
|
||||
if status["status"] == "completed":
|
||||
return True
|
||||
elif status["status"] == "failed":
|
||||
return False
|
||||
await asyncio.sleep(2)
|
||||
return False
|
||||
```
|
||||
|
||||
## 4. 完整流程时序
|
||||
|
||||
### 4.1 时序图
|
||||
|
||||
```
|
||||
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
|
||||
│ 微信 │ │ 节点 │ │ 中控 │ │ 客户端 │ │ 用户 │
|
||||
└────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘
|
||||
│ │ │ │ │
|
||||
│ 掉线 │ │ │ │
|
||||
│───────────────→│ │ │ │
|
||||
│ │ wechat_offline callback │ │
|
||||
│ │───────────────→│ │ │
|
||||
│ │ │ Webhook告警 │ │
|
||||
│ │ │───────────────→│ │
|
||||
│ │ │ │ │
|
||||
│ │ │ │ 获取二维码 │
|
||||
│ │ GET /qrcode │ │───────────────→│
|
||||
│ 返回二维码 │←──────────────│ │ │
|
||||
│←───────────────│ │ │ │
|
||||
│ │ │ │ 上传二维码 │
|
||||
│ │ │←──────────────│ │
|
||||
│ │ │ │ │
|
||||
│ │ │ 前端展示二维码│ │
|
||||
│ │ │───────────────→│ 扫码 │
|
||||
│ │ │ │←──────────────│
|
||||
│ 扫码确认 │ │ │ │
|
||||
│←───────────────│ │ │ │
|
||||
│ 登录成功 │ │ │ │
|
||||
│───────────────→│ │ │ │
|
||||
│ │ wechat_online callback │ │
|
||||
│ │───────────────→│ │ │
|
||||
│ │ │ 更新状态 │ │
|
||||
│ │ │───────────────→│ 完成 │
|
||||
```
|
||||
|
||||
### 4.2 详细步骤
|
||||
|
||||
| 步骤 | 参与者 | 操作 | API/协议 |
|
||||
|------|--------|------|----------|
|
||||
| 1 | 微信 | 掉线检测 | - |
|
||||
| 2 | 节点 | 回调通知中控 | POST /callback |
|
||||
| 3 | 中控 | 触发Webhook告警 | HTTP |
|
||||
| 4 | 客户端 | 接收告警 | POST /webhook/relogin |
|
||||
| 5 | 客户端 | 请求节点二维码 | GET /api/wechat/qrcode |
|
||||
| 6 | 节点 | 返回二维码图片 | HTTP |
|
||||
| 7 | 客户端 | 上传二维码到中控 | POST /callback/relogin/qrcode |
|
||||
| 8 | 中控 | 存储并通知前端 | WebSocket/轮询 |
|
||||
| 9 | 前端 | 展示二维码 | - |
|
||||
| 10 | 用户 | 扫码确认 | - |
|
||||
| 11 | 微信 | 登录成功 | - |
|
||||
| 12 | 节点 | 回调通知中控 | POST /callback |
|
||||
| 13 | 中控 | 更新节点状态 | - |
|
||||
|
||||
## 5. 数据库设计
|
||||
|
||||
### 5.1 新增表
|
||||
|
||||
```sql
|
||||
-- 节点重登录状态表
|
||||
CREATE TABLE node_relogin_status (
|
||||
id SERIAL PRIMARY KEY,
|
||||
node_id VARCHAR(50) UNIQUE NOT NULL,
|
||||
status VARCHAR(20) DEFAULT 'idle',
|
||||
qrcode_base64 TEXT,
|
||||
qrcode_expires_at TIMESTAMP,
|
||||
error_message TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 客户端配置表
|
||||
CREATE TABLE relogin_clients (
|
||||
id SERIAL PRIMARY KEY,
|
||||
client_name VARCHAR(100) NOT NULL,
|
||||
webhook_url VARCHAR(500) NOT NULL,
|
||||
secret_key VARCHAR(100),
|
||||
enabled BOOLEAN DEFAULT true,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
```
|
||||
|
||||
### 5.2 状态枚举
|
||||
|
||||
| 状态 | 说明 |
|
||||
|------|------|
|
||||
| `idle` | 空闲,无重登录任务 |
|
||||
| `waiting_qrcode` | 等待获取二维码 |
|
||||
| `qrcode_ready` | 二维码已就绪 |
|
||||
| `scanned` | 已扫码,待确认 |
|
||||
| `confirmed` | 已确认,登录中 |
|
||||
| `completed` | 登录完成 |
|
||||
| `failed` | 登录失败 |
|
||||
|
||||
## 6. API 接口详细设计
|
||||
|
||||
### 6.1 回调接口 - 接收二维码
|
||||
|
||||
```
|
||||
POST /api/v1/callback/relogin/qrcode
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"node_id": "wx1",
|
||||
"qrcode_base64": "data:image/png;base64,iVBORw0KGgo...",
|
||||
"expires_in": 120
|
||||
}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "二维码已接收"
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 查询重登录状态
|
||||
|
||||
```
|
||||
GET /api/v1/nodes/{node_id}/relogin/status
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"node_id": "wx1",
|
||||
"status": "qrcode_ready",
|
||||
"qrcode_base64": "data:image/png;base64,...",
|
||||
"qrcode_expires_at": "2026-04-07T15:30:00",
|
||||
"created_at": "2026-04-07T15:00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6.3 客户端注册
|
||||
|
||||
```
|
||||
POST /api/v1/relogin/clients
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"client_name": "服务器1",
|
||||
"webhook_url": "http://192.168.1.100:8081/webhook/relogin",
|
||||
"secret_key": "optional_secret"
|
||||
}
|
||||
```
|
||||
|
||||
### 6.4 客户端列表
|
||||
|
||||
```
|
||||
GET /api/v1/relogin/clients
|
||||
```
|
||||
|
||||
## 7. 安全考虑
|
||||
|
||||
### 7.1 客户端认证
|
||||
- 客户端注册时分配 secret_key
|
||||
- 回调接口需要携带签名验证
|
||||
- 中控可配置允许的客户端IP白名单
|
||||
|
||||
### 7.2 回调签名验证
|
||||
|
||||
```python
|
||||
import hmac
|
||||
import hashlib
|
||||
|
||||
def verify_signature(payload: bytes, signature: str, secret: str) -> bool:
|
||||
expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
|
||||
return hmac.compare_digest(expected, signature)
|
||||
```
|
||||
|
||||
## 8. 文件结构
|
||||
|
||||
```
|
||||
wxauto_api/
|
||||
├── plugins/
|
||||
│ └── wxautorelogin_plugin.py # 重登录插件
|
||||
├── api/
|
||||
│ └── relogin.py # 重登录相关API
|
||||
├── services/
|
||||
│ └── relogin_service.py # 重登录服务
|
||||
└── doc/
|
||||
└── wxautorelogin/
|
||||
├── README.md # 本文档
|
||||
├── CLIENT.md # 客户端开发指南
|
||||
└── API.md # API接口文档
|
||||
|
||||
wxauto-relogin-client/
|
||||
├── client/
|
||||
│ ├── __init__.py
|
||||
│ ├── webhook_server.py # Webhook接收服务
|
||||
│ ├── qrcode_handler.py # 二维码处理
|
||||
│ └── config.py # 配置
|
||||
├── requirements.txt
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## 9. 可行性结论
|
||||
|
||||
### 9.1 技术可行性:✅ 可行
|
||||
|
||||
1. **wxauto节点已提供QR码接口** - 通过 `/api/wechat/qrcode` 获取
|
||||
2. **中控已有回调机制** - 可复用现有 callback 系统
|
||||
3. **前端支持实时更新** - 可通过轮询或WebSocket展示二维码
|
||||
|
||||
### 9.2 实施难度:🟡 中等
|
||||
|
||||
1. 需要开发客户端程序
|
||||
2. 需要新增API接口
|
||||
3. 需要前端新增重登录页面
|
||||
|
||||
### 9.3 建议实施顺序
|
||||
|
||||
1. **Phase 1**: 中控端API开发
|
||||
2. **Phase 2**: 客户端程序开发
|
||||
3. **Phase 3**: 前端页面开发
|
||||
4. **Phase 4**: 整体联调测试
|
||||
|
||||
## 10. 后续优化方向
|
||||
|
||||
- 支持短信/邮件通知
|
||||
- 支持多客户端负载均衡
|
||||
- 支持扫码历史记录
|
||||
- 支持自动重试机制
|
||||
Reference in New Issue
Block a user