Initial commit: rdgen with GitHub/Gitea dual build backend
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
"""
|
||||
RustDesk 可选版本列表。
|
||||
|
||||
优先从 GitHub 官方仓库 rustdesk/rustdesk 的 tags 动态获取(跟随官方发版自动更新),
|
||||
进程内缓存 6 小时;网络失败时回退内置版本列表,且失败结果短缓存 10 分钟,
|
||||
避免每次打开页面都等待 GitHub 超时。所有请求经由 ghnet,自动使用代理配置。
|
||||
"""
|
||||
import re
|
||||
import time
|
||||
|
||||
from . import ghnet
|
||||
|
||||
TAGS_URL = 'https://api.github.com/repos/rustdesk/rustdesk/tags?per_page=100'
|
||||
|
||||
# 离线兜底(截至本版本发布时的近期正式版)
|
||||
FALLBACK_VERSIONS = [
|
||||
'1.4.9', '1.4.8', '1.4.7', '1.4.6', '1.4.5',
|
||||
'1.4.4', '1.4.3', '1.4.2', '1.4.1', '1.4.0',
|
||||
]
|
||||
|
||||
# 形如 1.4.9 / 1.4.10 / 1.5.0-rc.1 的正式 tag
|
||||
TAG_RE = re.compile(r'^\d+\.\d+\.\d+(?:[.-][0-9A-Za-z.]+)?$')
|
||||
# 表单/API 对用户提交版本号的宽松校验,兼容动态列表刷新窗口期
|
||||
VERSION_RE = re.compile(r'^(?:master|main|\d+\.\d+\.\d+(?:[.-][0-9A-Za-z.]+)?)$')
|
||||
|
||||
MAX_VERSIONS = 20
|
||||
CACHE_TTL = 6 * 3600 # 成功结果缓存 6 小时
|
||||
FALLBACK_TTL = 10 * 60 # 失败回退缓存 10 分钟
|
||||
|
||||
_memo = {
|
||||
'ts': 0.0,
|
||||
'ttl': CACHE_TTL,
|
||||
'versions': FALLBACK_VERSIONS,
|
||||
'source': 'builtin',
|
||||
}
|
||||
|
||||
|
||||
def _sort_versions(versions):
|
||||
"""按版本号数字段降序排列,预发布标识排在同正式版之后。"""
|
||||
def key(v):
|
||||
main, _, suffix = v.partition('-')
|
||||
parts = [int(x) if x.isdigit() else 0 for x in main.split('.')]
|
||||
parts += [0] * (3 - len(parts))
|
||||
# 无后缀(正式版)排在 rc/beta 之前
|
||||
return (parts, 1 if not suffix else 0, suffix)
|
||||
return sorted(versions, key=key, reverse=True)
|
||||
|
||||
|
||||
def _fetch_from_github():
|
||||
resp = ghnet.get(TAGS_URL, timeout=8)
|
||||
resp.raise_for_status()
|
||||
tags = [item['name'].lstrip('v') for item in resp.json() if item.get('name')]
|
||||
versions = _sort_versions({t for t in tags if TAG_RE.match(t)})
|
||||
return versions[:MAX_VERSIONS]
|
||||
|
||||
|
||||
def get_versions(force=False):
|
||||
"""返回 (版本号列表, 来源 source, 缓存时间戳);source: github / builtin。"""
|
||||
now = time.time()
|
||||
if not force and now - _memo['ts'] < _memo['ttl']:
|
||||
return _memo['versions'], _memo['source'], _memo['ts']
|
||||
|
||||
try:
|
||||
versions = _fetch_from_github()
|
||||
if versions:
|
||||
_memo.update(ts=now, ttl=CACHE_TTL, versions=versions, source='github')
|
||||
else:
|
||||
_memo.update(ts=now, ttl=FALLBACK_TTL, versions=FALLBACK_VERSIONS, source='builtin')
|
||||
except Exception:
|
||||
_memo.update(ts=now, ttl=FALLBACK_TTL, versions=FALLBACK_VERSIONS, source='builtin')
|
||||
return _memo['versions'], _memo['source'], _memo['ts']
|
||||
|
||||
|
||||
def version_choices():
|
||||
"""供 ChoiceField 使用的 (value, label) 列表。"""
|
||||
versions, source, _ = get_versions()
|
||||
label_suffix = '' if source == 'github' else '(内置列表,获取官方列表失败)'
|
||||
choices = [('master', '开发版(nightly 每夜构建)')]
|
||||
choices += [(v, v) for v in versions]
|
||||
return choices
|
||||
|
||||
|
||||
def is_valid_version(value):
|
||||
"""API / 表单提交的版本号合法性校验。"""
|
||||
return bool(value) and bool(VERSION_RE.match(str(value)))
|
||||
Reference in New Issue
Block a user