优化token刷新机制

This commit is contained in:
zhinianboke 2025-08-13 09:56:34 +08:00
parent a01648012b
commit 1cbf9fb745
6 changed files with 475 additions and 16 deletions

View File

@ -73,19 +73,121 @@ tests/
*.md *.md
docs/ docs/
# Docker相关 # Docker相关保留必要的构建文件
Dockerfile* .dockerignore.bak
docker-compose*.yml docker-compose.override.yml
.dockerignore
# 配置文件(运行时挂载) # 配置文件(运行时挂载)
# global_config.yml # global_config.yml
# 其他 # 环境变量文件
.env .env
.env.local .env.*
.env.*.local !.env.example
*.local.yml
*.dev.yml
*.test.yml
config.*.yml
!global_config.yml
# 前端相关
node_modules/ node_modules/
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
package-lock.json
yarn.lock
# 数据目录(运行时挂载)
data/
backups/
logs/
realtime.log
# 上传文件
static/uploads/*
!static/uploads/.gitkeep
!static/uploads/images/
static/uploads/images/*
!static/uploads/images/.gitkeep
# Excel和数据文件
*.xlsx
*.xls
*.csv
keywords_*.xlsx
export_*.csv
export_*.json
export_*.xlsx
# 压缩文件
*.zip
*.tar.gz
*.rar
*.7z
# 备份文件
*.bak
*.backup
*.old
# 密钥和证书
*.key
*.pem
*.crt
*.cert
*.p12
*.pfx
ssl/
secrets/
credentials/
# 运行时文件
*.pid
*.sock
*.lock
*.port
# 性能分析文件
*.prof
*.profile
*.pstats
# 缓存文件
.cache/
cache/
*.cache
# 浏览器相关
.playwright/
playwright-report/
test-results/
# 示例和演示文件
example_*.py
*_example.py
demo_*.py
*_demo.py
# AI模型文件
*.model
*.weights
*.h5
*.pb
# 大文件
*.iso
*.dmg
*.img
# 监控和审计
monitoring/
*.access.log
*.error.log
*.audit.log
# 本地开发文件
local/
.local/
debug.log
*.debug

100
.gitignore vendored
View File

@ -284,4 +284,102 @@ build/
# 大文件 # 大文件
*.iso *.iso
*.dmg *.dmg
*.img *.img
# ==================== 项目特定新增文件类型 ====================
# 测试和示例文件
test_*.py
*_test.py
example_*.py
*_example.py
demo_*.py
*_demo.py
# 文档文件除了README.md
*.md
!README.md
!CHANGELOG.md
!CONTRIBUTING.md
!LICENSE.md
# 临时配置文件
*.local.yml
*.dev.yml
*.test.yml
config.*.yml
!global_config.yml
# 运行时生成的文件
*.pid
*.lock
*.sock
*.port
# 性能和调试文件
*.profile
*.pstats
*.trace
# 编译和构建产物
*.whl
*.egg
*.tar.gz
build/
dist/
# 开发工具配置
.editorconfig
.flake8
.pylintrc
pyproject.toml
setup.cfg
tox.ini
# 容器相关
.dockerignore
docker-compose.*.yml
!docker-compose.yml
!docker-compose-cn.yml
# 安全相关
*.secret
*.token
*.auth
secrets/
credentials/
# 监控和日志
*.access.log
*.error.log
*.audit.log
monitoring/
# 第三方服务配置
.env
.env.*
!.env.example
# 数据导出文件
export_*.csv
export_*.json
export_*.xlsx
dump_*.sql
# 临时下载文件
downloads/
temp_downloads/
# 浏览器相关
.playwright/
playwright-report/
test-results/
# 系统服务文件
*.service
*.timer
systemd/
# 备份和归档
archive/
old/
deprecated/

View File

@ -429,6 +429,103 @@ python Start.py
- **`requirements.txt`** - Python依赖包列表精简版本无冗余依赖按功能分类组织包含详细说明 - **`requirements.txt`** - Python依赖包列表精简版本无冗余依赖按功能分类组织包含详细说明
- **`.gitignore`** - Git忽略文件配置完整覆盖Python、Docker、前端等开发文件 - **`.gitignore`** - Git忽略文件配置完整覆盖Python、Docker、前端等开发文件
- **`.dockerignore`** - Docker构建忽略文件优化构建上下文大小和构建速度 - **`.dockerignore`** - Docker构建忽略文件优化构建上下文大小和构建速度
- **`Dockerfile-cn`** - 国内优化版Docker镜像构建文件使用国内镜像源加速构建
- **`docker-compose-cn.yml`** - 国内优化版Docker Compose配置文件
## 🏗️ 详细技术架构
### 📊 系统架构图
```
┌─────────────────────────────────────────────────────────────────┐
│ Web前端界面 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 用户管理 │ │ 账号管理 │ │ 关键词管理 │ │ 商品管理 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 日志管理 │ │ 数据管理 │ │ 商品搜索 │ │ 系统监控 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ FastAPI Web服务器 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 用户认证 │ │ 权限管理 │ │ API接口 │ │ 文件上传 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 邮箱验证 │ │ 图形验证码 │ │ 实时日志 │ │ 健康检查 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ CookieManager 多账号管理器 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 任务调度 │ │ 状态监控 │ │ 线程管理 │ │ 异常处理 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ XianyuLive 实例集群 (多实例并行) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 账号A实例 │ │ 账号B实例 │ │ 账号C实例 │ │ ... │ │
│ │ WebSocket │ │ WebSocket │ │ WebSocket │ │ │ │
│ │ 消息处理 │ │ 消息处理 │ │ 消息处理 │ │ │ │
│ │ 自动回复 │ │ 自动回复 │ │ 自动回复 │ │ │ │
│ │ 自动发货 │ │ 自动发货 │ │ 自动发货 │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 辅助服务模块 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ AI回复引擎 │ │ 图片处理 │ │ 商品搜索 │ │ 订单处理 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 日志收集 │ │ 文件管理 │ │ 通知推送 │ │ 数据备份 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ SQLite数据库 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 用户数据 │ │ 账号数据 │ │ 关键词数据 │ │ 商品数据 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 发货数据 │ │ 系统设置 │ │ 日志数据 │ │ 统计数据 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
```
### 🔄 数据流程图
```
用户消息 → WebSocket接收 → 消息解析 → 关键词匹配 → 回复生成 → 消息发送
│ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼
商品识别 连接管理 内容过滤 AI处理 模板渲染 发送确认
│ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼
数据存储 状态监控 安全检查 上下文 变量替换 日志记录
```
### 🔐 安全架构
```
┌─────────────────────────────────────────────────────────────────┐
│ 安全防护层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ JWT认证 │ │ 权限控制 │ │ 数据加密 │ │ 访问控制 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 图形验证码 │ │ 邮箱验证 │ │ 会话管理 │ │ 操作日志 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
```
## ⚙️ 配置说明 ## ⚙️ 配置说明

View File

@ -170,6 +170,9 @@ class XianyuLive:
self.token_refresh_task = None self.token_refresh_task = None
self.connection_restart_flag = False # 连接重启标志 self.connection_restart_flag = False # 连接重启标志
# 从数据库获取token信息
self._load_token_info_from_db()
# 通知防重复机制 # 通知防重复机制
self.last_notification_time = {} # 记录每种通知类型的最后发送时间 self.last_notification_time = {} # 记录每种通知类型的最后发送时间
self.notification_cooldown = 300 # 5分钟内不重复发送相同类型的通知 self.notification_cooldown = 300 # 5分钟内不重复发送相同类型的通知
@ -191,6 +194,45 @@ class XianyuLive:
# 启动定期清理过期暂停记录的任务 # 启动定期清理过期暂停记录的任务
self.cleanup_task = None self.cleanup_task = None
def _load_token_info_from_db(self):
"""从数据库加载token信息"""
try:
from db_manager import db_manager
token_info = db_manager.get_token_info(self.cookie_id)
if token_info:
self.last_token_refresh_time = token_info.get('last_token_refresh_time', 0)
self.current_token = token_info.get('current_token', None)
logger.info(f"{self.cookie_id}】从数据库加载token信息成功 - 上次刷新时间: {self.last_token_refresh_time}, token: {'已设置' if self.current_token else '未设置'}")
else:
logger.info(f"{self.cookie_id}】数据库中未找到token信息使用默认值")
self.last_token_refresh_time = 0
self.current_token = None
except Exception as e:
logger.error(f"{self.cookie_id}】从数据库加载token信息失败: {self._safe_str(e)}")
# 使用默认值
self.last_token_refresh_time = 0
self.current_token = None
def _save_token_info_to_db(self):
"""保存token信息到数据库"""
try:
from db_manager import db_manager
success = db_manager.update_token_info(
self.cookie_id,
self.last_token_refresh_time,
self.current_token
)
if success:
logger.debug(f"{self.cookie_id}】token信息已保存到数据库")
else:
logger.warning(f"{self.cookie_id}】token信息保存到数据库失败")
except Exception as e:
logger.error(f"{self.cookie_id}】保存token信息到数据库异常: {self._safe_str(e)}")
def is_auto_confirm_enabled(self) -> bool: def is_auto_confirm_enabled(self) -> bool:
"""检查当前账号是否启用自动确认发货""" """检查当前账号是否启用自动确认发货"""
try: try:
@ -722,6 +764,10 @@ class XianyuLive:
new_token = res_json['data']['accessToken'] new_token = res_json['data']['accessToken']
self.current_token = new_token self.current_token = new_token
self.last_token_refresh_time = time.time() self.last_token_refresh_time = time.time()
# 保存token信息到数据库
self._save_token_info_to_db()
logger.info(f"{self.cookie_id}】Token刷新成功") logger.info(f"{self.cookie_id}】Token刷新成功")
return new_token return new_token
@ -750,8 +796,15 @@ class XianyuLive:
if hasattr(self, 'user_id') and self.user_id: if hasattr(self, 'user_id') and self.user_id:
current_user_id = self.user_id current_user_id = self.user_id
db_manager.save_cookie(self.cookie_id, self.cookies_str, current_user_id) # 保存cookies和token信息
logger.debug(f"已更新Cookie到数据库: {self.cookie_id}") db_manager.save_cookie(
self.cookie_id,
self.cookies_str,
current_user_id,
self.last_token_refresh_time,
self.current_token
)
logger.debug(f"已更新Cookie和token信息到数据库: {self.cookie_id}")
except Exception as e: except Exception as e:
logger.error(f"更新数据库Cookie失败: {self._safe_str(e)}") logger.error(f"更新数据库Cookie失败: {self._safe_str(e)}")
# 发送数据库更新失败通知 # 发送数据库更新失败通知

View File

@ -115,10 +115,27 @@ class DBManager:
auto_confirm INTEGER DEFAULT 1, auto_confirm INTEGER DEFAULT 1,
remark TEXT DEFAULT '', remark TEXT DEFAULT '',
pause_duration INTEGER DEFAULT 10, pause_duration INTEGER DEFAULT 10,
last_token_refresh_time REAL DEFAULT 0,
current_token TEXT DEFAULT '',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) )
''') ''')
# 为现有的cookies表添加新字段如果不存在
try:
cursor.execute('ALTER TABLE cookies ADD COLUMN last_token_refresh_time REAL DEFAULT 0')
logger.info("已为cookies表添加last_token_refresh_time字段")
except sqlite3.OperationalError:
# 字段已存在,忽略错误
pass
try:
cursor.execute('ALTER TABLE cookies ADD COLUMN current_token TEXT DEFAULT ""')
logger.info("已为cookies表添加current_token字段")
except sqlite3.OperationalError:
# 字段已存在,忽略错误
pass
# 创建keywords表 # 创建keywords表
cursor.execute(''' cursor.execute('''
@ -1063,7 +1080,8 @@ class DBManager:
return cursor.executemany(sql, params_list) return cursor.executemany(sql, params_list)
# -------------------- Cookie操作 -------------------- # -------------------- Cookie操作 --------------------
def save_cookie(self, cookie_id: str, cookie_value: str, user_id: int = None) -> bool: def save_cookie(self, cookie_id: str, cookie_value: str, user_id: int = None,
last_token_refresh_time: float = None, current_token: str = None) -> bool:
"""保存Cookie到数据库如存在则更新""" """保存Cookie到数据库如存在则更新"""
with self.lock: with self.lock:
try: try:
@ -1081,10 +1099,38 @@ class DBManager:
admin_user = cursor.fetchone() admin_user = cursor.fetchone()
user_id = admin_user[0] if admin_user else 1 user_id = admin_user[0] if admin_user else 1
self._execute_sql(cursor, # 如果提供了token相关信息则更新这些字段
"INSERT OR REPLACE INTO cookies (id, value, user_id) VALUES (?, ?, ?)", if last_token_refresh_time is not None or current_token is not None:
(cookie_id, cookie_value, user_id) # 先获取现有记录的token信息
) self._execute_sql(cursor,
"SELECT last_token_refresh_time, current_token FROM cookies WHERE id = ?",
(cookie_id,))
existing_token_info = cursor.fetchone()
if existing_token_info:
# 如果没有提供新值,使用现有值
if last_token_refresh_time is None:
last_token_refresh_time = existing_token_info[0]
if current_token is None:
current_token = existing_token_info[1]
else:
# 如果没有现有记录,使用默认值
if last_token_refresh_time is None:
last_token_refresh_time = 0
if current_token is None:
current_token = ''
self._execute_sql(cursor,
"INSERT OR REPLACE INTO cookies (id, value, user_id, last_token_refresh_time, current_token) VALUES (?, ?, ?, ?, ?)",
(cookie_id, cookie_value, user_id, last_token_refresh_time, current_token)
)
else:
# 如果没有提供token信息保持现有的token信息不变
self._execute_sql(cursor,
"INSERT OR REPLACE INTO cookies (id, value, user_id) VALUES (?, ?, ?)",
(cookie_id, cookie_value, user_id)
)
self.conn.commit() self.conn.commit()
logger.info(f"Cookie保存成功: {cookie_id} (用户ID: {user_id})") logger.info(f"Cookie保存成功: {cookie_id} (用户ID: {user_id})")
@ -1100,6 +1146,69 @@ class DBManager:
logger.error(f"Cookie保存失败: {e}") logger.error(f"Cookie保存失败: {e}")
self.conn.rollback() self.conn.rollback()
return False return False
def update_token_info(self, cookie_id: str, last_token_refresh_time: float = None, current_token: str = None) -> bool:
"""更新Cookie的token信息"""
with self.lock:
try:
cursor = self.conn.cursor()
# 构建动态SQL语句
update_fields = []
params = []
if last_token_refresh_time is not None:
update_fields.append("last_token_refresh_time = ?")
params.append(last_token_refresh_time)
if current_token is not None:
update_fields.append("current_token = ?")
params.append(current_token)
if not update_fields:
logger.warning(f"没有提供要更新的token信息: {cookie_id}")
return True
params.append(cookie_id)
sql = f"UPDATE cookies SET {', '.join(update_fields)} WHERE id = ?"
self._execute_sql(cursor, sql, params)
self.conn.commit()
if cursor.rowcount > 0:
logger.debug(f"Token信息更新成功: {cookie_id}")
return True
else:
logger.warning(f"未找到要更新的Cookie记录: {cookie_id}")
return False
except Exception as e:
logger.error(f"Token信息更新失败: {e}")
self.conn.rollback()
return False
def get_token_info(self, cookie_id: str) -> Optional[Dict[str, any]]:
"""获取Cookie的token信息"""
with self.lock:
try:
cursor = self.conn.cursor()
self._execute_sql(cursor,
"SELECT last_token_refresh_time, current_token FROM cookies WHERE id = ?",
(cookie_id,))
result = cursor.fetchone()
if result:
return {
'last_token_refresh_time': result[0] if result[0] is not None else 0,
'current_token': result[1] if result[1] is not None else ''
}
else:
logger.warning(f"未找到Cookie记录: {cookie_id}")
return None
except Exception as e:
logger.error(f"获取Token信息失败: {e}")
return None
def delete_cookie(self, cookie_id: str) -> bool: def delete_cookie(self, cookie_id: str) -> bool:
"""从数据库删除Cookie及其关键字""" """从数据库删除Cookie及其关键字"""

View File

@ -59,7 +59,7 @@ MANUAL_MODE:
toggle_keywords: [] toggle_keywords: []
MESSAGE_EXPIRE_TIME: 300000 MESSAGE_EXPIRE_TIME: 300000
TOKEN_REFRESH_INTERVAL: 18000 # 从3600秒(1小时)增加到18000秒(5小时) TOKEN_REFRESH_INTERVAL: 18000 # 从3600秒(1小时)增加到18000秒(5小时)
TOKEN_RETRY_INTERVAL: 1800 # 从300秒(5分钟)增加到1800秒(30分钟) TOKEN_RETRY_INTERVAL: 7200 # 从300秒(5分钟)增加到7200秒(2小时)
WEBSOCKET_HEADERS: WEBSOCKET_HEADERS:
Accept-Encoding: gzip, deflate, br, zstd Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: zh-CN,zh;q=0.9 Accept-Language: zh-CN,zh;q=0.9