Files

86 lines
3.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
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)))