点击关注我的Telegram群组和微信公众号

MENU

使用FastAPI为开源程序设计更新分发系统

2022 年 03 月 29 日 • 阅读: 2079 • 技术,教程

前言

最近为 Snap Genshin 写了一个后端程序用于分发版本更新,几次更新后使用稳定,故写此文作为经验总结。Snap Genshin 是一个在 GitHub 上开源的 Windows 客户端程序,在设计更新分发系统之前使用 GitHub API 获取版本信息和更新包下载链接。但是这种顺理成章的解决方案依赖于用户客户端与 GitHub 服务器之间的连接稳定性,这对于主要用户位于中国大陆地区的程序而言是不太现实的。使用 FastGit 可以增加这种方案的实施有效性,但对方也是一个免费的开源项目,终究也不是一个稳妥的方案。
简而言之,这个系统需要达到以下目标:

  1. 在中国大陆地区有稳定的连通性,下载速度能保证用户在 20 秒内下载约 14MB 大小的安装包
  2. 需要保证海外用户同样有可靠的用户体验
  3. 成本可控
  4. 自动化跟踪更新

设计

在新的方案中,后端 API 处理版本信息,而世纪互联 OneDrive 因稳定的服务质量被用于中国大陆地区的程序分发来源

资源存放

世纪互联 OneDrive 有多个值得选择它的理由

  1. 提供开发者 API,且已有很多开源软件完成了对接(这一点就秒杀绝大多数服务商了)
  2. 在包括中国大陆在内所有地区都有顺畅的体验
  3. 价格合理,无额外的按量付费
  4. 基于第一点,我们可以通过永不过期直链访问文件(这也是分发程序)

在服务器上,我们部署 OneManager-PHP 作为 OneDrive 的网页列目录程序。该程序允许在携带 admin cookie 的情况下远程执行 /refreshCache 方法以及时刷新目录缓存。该程序的 cookie 生成逻辑也很简单(代码如下),很容易就可以生成一个长时间不过期的 cookie 以应用于自动化流程的执行

  • function adminpass2cookie($name, $pass, $timestamp)
  • {
  • return md5($name . ':' . md5($pass) . '@' . $timestamp) . "(" . $timestamp . ")";
  • }

资源上传

Snap Genshin 的版本发布依旧依赖 GitHub Release,所以我们可以在 release 发布时执行一个 GitHub Action,通过 rclone 的方式挂载 OneDrive 并复制新版本软件包到云端。核心代码如下,其中 { secrets.RCCONF } 为 rclone 的帐号配置文件的完整内容:

  • - name: Upload OD21
  • env:
  • RCCONF: ${{ secrets.RCCONF }}
  • run: |
  • curl https://rclone.org/install.sh | sudo bash
  • mkdir -p ~/.config/rclone/
  • cat << EOF > ~/.config/rclone/rclone.conf
  • $RCCONF
  • EOF
  • rclone delete od21:/snapgenshin/Publish.zip
  • rclone copy ./release-download/Publish.zip od21:/snapgenshin/

同时,在上传完成后,我们通过 curl 远程执行 OneManager 的缓存刷新任务。代码如下,其中 { secrets.ADMINCOOKIE } 为 OneManager 的 admin cookie

  • - name: Refresh cache
  • env:
  • ADMINCOOKIE: ${{ secrets.ADMINCOOKIE }}
  • run: |
  • curl --cookie "admin=$ADMINCOOKIE" "https://resource.snapgenshin.com/?RefreshCache"

构建后端程序

后端程序使用 Python 的 FastAPI 库完成,已经开源于 DGP-Studio/Snap.Genshin.WebAPI

  • refreshPatchMeta 方法会通过 GitHub API 获取到目标库的 release 信息,并在一定时间内对该数据进行缓存
  • checkPatchMetaExpiration 方法会检查缓存是否超过了设置的缓存过期时间
  • forceRefreshCache 方法作为 API 允许管理员远程强制刷新后端缓存
  • getPatchGlobal 方法作为 API 将返回最新的主程序版本号和 GitHub Release 下载链接
  • getPatchCN 方法作为 API 将返回最新的主程序版本号,和 OneManager 网站中的主程序下载链接,该 API 被设计专用于中国大陆地区用户的版本分发

至此,我们得到了如下三个 API 接口
API接口列表接着,我们创建两个 Nginx 配置文件,使用两个不同的二级域名分别指向上述两个 GET 接口,我们将其命名为 patch-global.snapgenshin.compatch-cn.snapgenshin.com,这样我们就可以通过访问这两个二级域名来获得不同地区的版本分发结果了。其中,patch-global.snapgenshin.com 的反代配置文件如下所示:

  • location /getPatch {
  • proxy_pass http://127.0.0.1:3051/patch/stable/global;
  • #proxy_set_header Host 127.0.0.1; # Only if you need to override default host
  • proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  • proxy_set_header X-Forwarded-Host $host:$server_port;
  • proxy_set_header X-Forwarded-Proto $scheme;
  • proxy_set_header X-Forwarded-Server $host;
  • proxy_set_header X-Real-IP $remote_addr;
  • }

配置 CDN

两个不同的版本分发域名会导致混乱,也要求客户端去做其不擅长的用户地域判断。因此,我们需要创建一个统一的版本更新请求接口,并在 DNS 层面对不同地域的用户进行划分。在国内外使用不同的 CDN 运营商能让我们更轻松地解决这个问题。

  • 在中国 CDN 中

    • 我们将 patch.snapgenshin.com 域名绑定
    • 回源地址填写为服务器 IP
    • 回源 Hostname 填写为 patch-cn.snapgenshin.com
    • 设置接口缓存 3 分钟
    • 获得来自 CDN 服务商的 cname 地址 cn.cdn.network
  • 在海外 CDN 中

    • 我们将 patch.snapgenshin.com 域名绑定
    • 回源地址填写为服务器 IP
    • 回源 Hostname 填写为 patch-global.snapgenshin.com
    • 设置接口缓存 3 分钟
    • 获得来自 CDN 服务商的 cname 地址 global.cdn.network

接下来我们将 patch.snapgenshin.com 按地域解析到对应的 CDN 服务商即可

  • 对中国大陆地区,我们设置域名以 cname 方式解析到 cn.cdn.network
  • 对其他地区(默认解析),我们设置域名以 cname 方式解析到 global.cdn.network

至此,我们就完成了一个能分发下载速度最佳服务器的版本分发系统
在中国大陆访问接口,你将看到如下的结果:
cn patch API在其它地区访问接口,你将看到如下的结果:
global patch API

碎碎念

这套后端程序系统在 3 月初就已完工,文章本来预期在 3 月 20 日左右发布。拖到月底才完成一是其它项目带来的额外工作量,二是难以决定这篇文档该如何定位:后端程序的逻辑并不复杂,因此不能依靠它来介绍 FastAPI;整套系统包含了很多经验之谈,技术内容也没多少,它的实现其实更像是一种奇技淫巧。但是,它终究是被写出来了,因为在中国兼顾用户体验和低成本的开源程序分发确实存在难度。Gitee 连下载 release 都需要登录,代码内容都需要做审查,只想做中国式的封闭平台,何以成大事。
在软件设计时,我们需要将用户假想成几乎没有计算机知识的人,所以功能实现的方法需要尽可能简单。Windows 下的程序不像 Android/iOS 那样可以依靠应用商店来做到分发更新,唯有内置更新组件来实现版本推送。一个有理想、有经验的开发者不会将其软件分发置于百度云盘那样的公有云储存平台,文件提取码、强制客户端下载这样的限制会让急性子的新用户很快失去对程序的兴趣。有经验的开发者也不会完全指望 GitHub 向中国用户分发程序,因为大多数用户都无法连接到目标服务器。希望这篇文章能够帮助到正在寻找版本分发解决方案的开源程序开发者。

返回文章列表 文章二维码 打赏
本页链接的二维码
打赏二维码
添加新评论

  • OωO
  • |´・ω・)ノ
  • ヾ(≧∇≦*)ゝ
  • (☆ω☆)
  • (╯‵□′)╯︵┴─┴
  •  ̄﹃ ̄
  • (/ω\)
  • ∠( ᐛ 」∠)_
  • (๑•̀ㅁ•́ฅ)
  • →_→
  • ୧(๑•̀⌄•́๑)૭
  • ٩(ˊᗜˋ*)و
  • (ノ°ο°)ノ
  • (´இ皿இ`)
  • ⌇●﹏●⌇
  • (ฅ´ω`ฅ)
  • (╯°A°)╯︵○○○
  • φ( ̄∇ ̄o)
  • ヾ(´・ ・`。)ノ"
  • ( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
  • (ó﹏ò。)
  • Σ(っ °Д °;)っ
  • ( ,,´・ω・)ノ"(´っω・`。)
  • ╮(╯▽╰)╭
  • o(*////▽////*)q
  • >﹏<
  • ( ๑´•ω•) "(ㆆᴗㆆ)
  • (。•ˇ‸ˇ•。)
  • 妖梦
  • 泡泡
  • 阿鲁
  • 颜文字