5.1 KiB
5.1 KiB
2026-05-29 推送页面迭代 Round 2 — 技术文档
涉及文件清单
| 文件 | 改动类型 | 涉及功能 |
|---|---|---|
server/infrastructure/telegram/__init__.py |
新增函数 | F3 Telegram |
server/application/services/sync_engine_v2.py |
修改 | F1 重试 + F3 Telegram |
server/api/websocket.py |
修改参数 | F1 重试 |
server/api/sync_v2.py |
新增端点 | F4 预览 |
server/api/schemas.py |
新增模型 | F4 预览 |
web/app/push.html |
修改 | F1+F2+F4+F5 前端 |
docs/changelog/2026-05-29-push-round2.md |
新增 | changelog |
实现步骤
Step 1: F5 同步模式详细说明(纯前端)
文件: web/app/push.html
- 同步模式
</div>后增加<div id="syncModeDesc">说明文字 onSyncModeChange()函数末尾增加说明文字更新逻辑- 默认显示增量同步说明
说明内容:
- 增量同步:仅传输源目录中新增或修改的文件,目标已有且未变的文件跳过。安全快速,适合日常更新。
- 全量同步:使目标目录与源目录完全一致,会删除目标中不存在于源的文件。⚠️ 可能造成数据丢失,建议先预览。
- 校验和:通过文件内容校验和(而非修改时间+大小)判断是否需要传输。更精确但更慢,适合时钟不同步的环境。
Step 2: F2 服务器在线状态标识(纯前端)
文件: web/app/push.html
filterServers()中渲染<option>时,根据s.is_online加🟢/🔴前缀- 离线服务器选项加
style="color: #666"提示 - 数据来源:
/api/servers/已返回is_online(从 Redis heartbeat 实时读取),无需改后端
Step 3: F1 失败自动重试(后端+前端)
后端:
-
server/application/services/sync_engine_v2.py—_sync_one():- 当
sync_log.status == "failed"时,创建PushRetryJob:retry_job = PushRetryJob( server_id=server.id, server_name=server.name, source_path=source_path, target_path=dest, status="pending", retry_count=0, max_retries=3, next_retry_at=datetime.now(timezone.utc), last_error=sync_log.error_message[:500] if sync_log.error_message else None, ) retry_job = await self.retry_repo.create(retry_job) - 将
retry_job.id存入变量,传给 WS 广播
- 当
-
server/api/websocket.py—broadcast_sync_progress()增加参数:retry_job_id: int = None- WS 消息中增加
retry_job_id字段
前端:
updateProgressFromWS()— 失败行渲染"🔄 重试"按钮updateProgressFromResult()— 同上- 新增
retryServer(retryJobId)— 调用POST /api/retries/{id}/retry - 存储映射
_retryJobMap = {}—server_id → retry_job_id
Step 4: F3 推送完成 Telegram 通知(后端)
-
server/infrastructure/telegram/__init__.py— 新增函数:async def send_telegram_sync_complete( completed: int, failed: int, total: int, source_path: str, operator: str, failed_servers: list[str] = None, duration_seconds: int = None, ) -> bool:- 消息格式:HTML,含 emoji 标识状态
- 全部成功: 🟢 推送完成
- 部分失败: 🟡 推送完成(部分失败)+ 失败服务器名列表
- 全部失败: 🔴 推送失败
source_path经sanitize_external_message()脱敏
-
server/application/services/sync_engine_v2.py—sync_files():asyncio.gather()完成后,计算总耗时- 收集失败服务器名列表
- 调用
send_telegram_sync_complete() - try/except 包裹,Telegram 失败不影响推送结果
Step 5: F4 文件内容预览(后端+前端)
后端:
-
server/api/schemas.py— 新增:class LocalFilePreview(BaseModel): path: str = Field(..., min_length=1) -
server/api/sync_v2.py— 新增POST /api/sync/local-file-preview:- 安全:
os.path.realpath()+startswith("/tmp/nexus_upload_") - 限制:仅文件(非目录)+ 最多读 4KB
- 返回:
{name, size, content_base64, truncated, encoding_hint} encoding_hint: 尝试 UTF-8 解码,成功"text"否则"binary"- 审计日志
- 安全:
前端:
renderFileManager()— 文件名加cursor-pointer+onclick="previewLocalFile(path, name)"- 新增
previewLocalFile(path, name):- 调用
/api/sync/local-file-preview - 弹出模态框显示文件名、大小、内容
- 二进制文件提示"无法预览"
- 调用
- 新增模态框 HTML:
#previewModal
依赖与配置变更
无新依赖。无数据库 schema 迁移。
测试要点
- F5: 切换同步模式 → 说明文字正确切换
- F2: 在线服务器🟢、离线服务器🔴显示正确
- F1: 推送失败 → 行内重试按钮 → 点击重试成功
- F3: 推送完成 → Telegram 收到通知
- F4: 点击文件 → 预览模态框显示内容
- F4: 点击二进制文件 → 提示无法预览
- F4 安全: 尝试预览
/etc/passwd→ 403 拒绝
回滚方式
所有改动均为增量(新增函数/端点/前端元素),回滚只需:
git revert提交supervisorctl restart nexus