feat: 完善服务端工程化、发布流程和自动化测试

This commit is contained in:
2026-07-16 08:36:12 +00:00
parent 0b71e8d024
commit 5d7aa560e5
29 changed files with 822 additions and 7987 deletions
+8
View File
@@ -45,6 +45,8 @@ def normalize_relative_path(raw_path: str) -> str:
@router.post("/api/v1/device/issue")
async def issue_device(request: Request, body: DeviceIssueRequest = Body(...)):
# 设备登记:客户端首次启动时用 License 换取服务端签名的设备凭证。
# 后续更新接口依赖这个凭证里的 app_id/channel/device_id/license_id,而不是只相信客户端自报字段。
app_id, channel, installation_id = body.app_id.strip(), body.channel.strip(), body.installation_id.strip()
if not app_id or not validate_channel_code(channel) or not (16 <= len(installation_id) <= 128):
raise HTTPException(status_code=400, detail="设备登记参数无效")
@@ -90,6 +92,8 @@ async def issue_device(request: Request, body: DeviceIssueRequest = Body(...)):
@router.post("/api/v1/update/check")
async def check_update(request: Request, body: CheckUpdateRequest = Body(...)):
# 更新检查同时返回“能不能运行”和“要不要更新”。
# 客户端即使没有新版本,也会拿到签名策略,用于离线启动、禁用版本和防回滚判断。
if request.state.device_identity["app_id"] != body.app_id or request.state.device_identity["channel"] != body.channel:
raise HTTPException(status_code=403, detail="设备凭证与应用/渠道不匹配")
app_id, cur_ver, channel = body.app_id, body.current_version, body.channel
@@ -176,6 +180,8 @@ async def check_update(request: Request, body: CheckUpdateRequest = Body(...)):
@router.post("/api/v1/update/download-url")
async def get_download_url(request: Request, body: DownloadUrlRequest = Body(...)):
# 下载链接不直接暴露 MinIO 永久地址,而是按版本和设备凭证生成短期可用的预签名 URL。
# 这样既能让客户端直接下载大文件,又能保留服务端授权控制。
identity = request.state.device_identity
if identity["app_id"] != body.app_id or identity["channel"] != body.channel:
raise HTTPException(status_code=403, detail="设备凭证与应用/渠道不匹配")
@@ -213,6 +219,8 @@ async def report_download(request: Request, body: DownloadReportRequest = Body(.
@router.post("/api/v1/update/manifest")
async def get_manifest(request: Request, body: ManifestRequest = Body(...)):
# Manifest 是某个版本的文件清单:路径、大小、SHA256、是否可执行。
# 客户端必须先验证服务端签名,再按清单下载和校验文件,防止升级包被篡改。
if request.state.device_identity["app_id"] != body.app_id or request.state.device_identity["channel"] != body.channel:
raise HTTPException(status_code=403, detail="设备凭证与应用/渠道不匹配")
ver, rows = client_update_repository.get_manifest_version_files(body.version_id)