updater.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. """
  2. 更新服务API
  3. 提供客户端版本检测和更新包下载服务
  4. """
  5. from fastapi import APIRouter, HTTPException, Query
  6. from fastapi.responses import FileResponse
  7. from typing import Dict, Any
  8. import os
  9. import json
  10. from datetime import datetime
  11. from app.utils.timezone import beijing_now
  12. router = APIRouter()
  13. # 模拟版本信息存储(实际应该存储在数据库中)
  14. CURRENT_VERSION = "1.0.0"
  15. UPDATE_INFO = {
  16. "version": "1.0.1",
  17. "notes": "修复了扫货功能bug,提升了稳定性",
  18. "pub_date": "2026-01-01T10:00:00Z",
  19. "platforms": {
  20. "windows-x86_64": {
  21. "signature": "更新包数字签名",
  22. "url": "https://api.youdangdang.com/updates/windows-x86_64/1.0.1/update.exe",
  23. "size": 52428800 # 50MB
  24. },
  25. "darwin-x86_64": {
  26. "signature": "更新包数字签名",
  27. "url": "https://api.youdangdang.com/updates/darwin-x86_64/1.0.1/update.dmg",
  28. "size": 67108864 # 64MB
  29. },
  30. "linux-x86_64": {
  31. "signature": "更新包数字签名",
  32. "url": "https://api.youdangdang.com/updates/linux-x86_64/1.0.1/update.AppImage",
  33. "size": 41943040 # 40MB
  34. }
  35. }
  36. }
  37. @router.get("/updates/{target}/{current_version}")
  38. async def check_update(
  39. target: str,
  40. current_version: str,
  41. current_app_version: str = Query(None, alias="currentAppVersion"),
  42. current_bundle_version: str = Query(None, alias="currentBundleVersion")
  43. ) -> Dict[str, Any]:
  44. """
  45. 检查更新API - Tauri客户端调用此接口检测更新
  46. Args:
  47. target: 目标平台 (windows-x86_64, darwin-x86_64, linux-x86_64)
  48. current_version: 当前版本
  49. current_app_version: 当前应用版本
  50. current_bundle_version: 当前包版本
  51. Returns:
  52. 更新信息或204 No Content(无更新)
  53. """
  54. try:
  55. # 检查目标平台是否支持
  56. if target not in UPDATE_INFO["platforms"]:
  57. raise HTTPException(status_code=400, detail=f"Unsupported target: {target}")
  58. # 版本比较逻辑(简化版,实际需要更复杂的版本比较)
  59. if current_version >= UPDATE_INFO["version"]:
  60. # 返回204表示无更新
  61. return {"status": "no-update"}
  62. # 返回更新信息
  63. platform_info = UPDATE_INFO["platforms"][target]
  64. return {
  65. "version": UPDATE_INFO["version"],
  66. "notes": UPDATE_INFO["notes"],
  67. "pub_date": UPDATE_INFO["pub_date"],
  68. "platforms": {
  69. target: platform_info
  70. }
  71. }
  72. except Exception as e:
  73. raise HTTPException(status_code=500, detail=f"Update check failed: {str(e)}")
  74. @router.get("/updates/download/{target}/{version}/{filename}")
  75. async def download_update(target: str, version: str, filename: str):
  76. """
  77. 下载更新包
  78. Args:
  79. target: 目标平台
  80. version: 版本号
  81. filename: 文件名
  82. Returns:
  83. 更新包文件
  84. """
  85. # 实际实现中,这里应该从文件存储系统(如OSS、S3等)下载文件
  86. # 这里只是示例代码
  87. file_path = f"/path/to/updates/{target}/{version}/{filename}"
  88. if not os.path.exists(file_path):
  89. raise HTTPException(status_code=404, detail="Update file not found")
  90. return FileResponse(
  91. path=file_path,
  92. filename=filename,
  93. media_type="application/octet-stream"
  94. )
  95. @router.post("/updates/force/{user_id}")
  96. async def force_update_user(user_id: int, version: str = None):
  97. """
  98. 强制指定用户更新到指定版本
  99. Args:
  100. user_id: 用户ID
  101. version: 目标版本(可选,默认最新版本)
  102. Returns:
  103. 操作结果
  104. """
  105. # 实际实现中,需要在数据库中标记用户需要强制更新
  106. # 客户端在下次启动时会检测到强制更新标志
  107. target_version = version or UPDATE_INFO["version"]
  108. # 数据库操作:更新用户的强制更新标志
  109. # user.force_update_version = target_version
  110. # user.force_update_required = True
  111. return {
  112. "success": True,
  113. "message": f"User {user_id} will be forced to update to version {target_version}",
  114. "target_version": target_version
  115. }
  116. @router.get("/admin/updates/stats")
  117. async def get_update_stats():
  118. """
  119. 获取更新统计信息(管理员接口)
  120. Returns:
  121. 更新统计数据
  122. """
  123. # 实际实现中,从数据库查询更新统计信息
  124. return {
  125. "current_version": CURRENT_VERSION,
  126. "latest_version": UPDATE_INFO["version"],
  127. "total_users": 1000,
  128. "updated_users": 850,
  129. "update_rate": "85%",
  130. "platforms": {
  131. "windows": {"users": 600, "updated": 520},
  132. "macos": {"users": 300, "updated": 280},
  133. "linux": {"users": 100, "updated": 50}
  134. }
  135. }