修复:

- PAC 数据更新源改为直接拉取数据文件(原 manifest 方案简化,文件自带资源号/日期)
- 远端数据缺少版本号时改为按内容比对,避免每次启动重复下载

新增功能:
- 配置真实 PAC CDN 地址(cdn.rrrosmontis.icu)
This commit is contained in:
RoyirinRosmontis
2026-08-23 12:19:17 +08:00
parent 254f78cc04
commit e8f3d8b645
+33 -29
View File
@@ -536,8 +536,7 @@ _TLS_LOCAL_PORT = int(_config_val("local_port", 1080)) # 本地转发器监听
PROXY_PORT = _TLS_LOCAL_PORT PROXY_PORT = _TLS_LOCAL_PORT
# ── PAC 数据在线更新(CDN 直连,无需认证) ───────────── # ── PAC 数据在线更新(CDN 直连,无需认证) ─────────────
# 更新源地址取 config.json 的 pac_base_url;目录结构: # 更新源地址取 config.json 的 pac_base_url,目录下直接放两个数据文件:
# {pac_base_url}/pac_manifest.json 资源号清单
# {pac_base_url}/pac_domains.json 强制隧道域名表(version/date 字段随文件下发) # {pac_base_url}/pac_domains.json 强制隧道域名表(version/date 字段随文件下发)
# {pac_base_url}/pac_ip_cn.json 中国 IP 段(同上) # {pac_base_url}/pac_ip_cn.json 中国 IP 段(同上)
_PAC_FILES = ("pac_domains", "pac_ip_cn") _PAC_FILES = ("pac_domains", "pac_ip_cn")
@@ -574,17 +573,13 @@ def _pac_validate(name, data):
return isinstance(data.get("cidrs"), list) return isinstance(data.get("cidrs"), list)
return False return False
def _pac_download(base, name): def _pac_write(name, data):
"""下载 PAC 数据并原子写入 ~/RRPP;返回 (version, date)。""" """PAC 数据原子写入 ~/RRPP(tmp+replace,写不坏旧文件)。"""
import json import json
data = _pac_fetch_json(f"{base}/{name}.json")
if not _pac_validate(name, data):
raise ValueError(f"{name}.json 数据格式不正确")
_USER_DIR.mkdir(parents=True, exist_ok=True) _USER_DIR.mkdir(parents=True, exist_ok=True)
tmp = _USER_DIR / f"{name}.json.tmp" tmp = _USER_DIR / f"{name}.json.tmp"
tmp.write_text(json.dumps(data, ensure_ascii=False), "utf-8") tmp.write_text(json.dumps(data, ensure_ascii=False), "utf-8")
os.replace(tmp, _USER_DIR / f"{name}.json") # 原子替换,避免写一半 os.replace(tmp, _USER_DIR / f"{name}.json")
return str(data.get("version") or ""), str(data.get("date") or "")
def _user_init_local(): def _user_init_local():
"""初始化 ~/RRPP(同步):建目录,nodes.json 缺失时写入空模板。""" """初始化 ~/RRPP(同步):建目录,nodes.json 缺失时写入空模板。"""
@@ -599,35 +594,44 @@ def _user_init_local():
def _user_init_remote(base_url=None, nodes_url=None): def _user_init_remote(base_url=None, nodes_url=None):
"""检查并更新 PAC 数据与节点配置(后台线程): """检查并更新 PAC 数据与节点配置(后台线程):
PAC 按 manifest 版本比对(失败用本地副本);nodes 按内容比对(独立地址)。 PAC 直接拉取两个数据文件(内含 version/date),按版本比对后更新;失败用本地副本。
nodes 按内容比对(独立地址)。
""" """
base = (base_url or str(_config_val("pac_base_url", "") or "")).strip().rstrip("/") base = (base_url or str(_config_val("pac_base_url", "") or "")).strip().rstrip("/")
if not base: if not base:
log("未配置 PAC 更新源(config.json 的 pac_base_url),使用本地数据") log("未配置 PAC 更新源(config.json 的 pac_base_url),使用本地数据")
else: else:
try: import json
manifest = _pac_fetch_json(f"{base}/pac_manifest.json") updated = failed = 0
except Exception as e: for name in _PAC_FILES:
log(f"PAC 更新源不可达,使用本地数据 ({e})") try:
manifest = None data = _pac_fetch_json(f"{base}/{name}.json")
if manifest is not None: if not _pac_validate(name, data):
updated = 0 raise ValueError(f"{name}.json 数据格式不正确")
for name in _PAC_FILES: rver = str(data.get("version") or "")
remote = manifest.get(name) or {} rdate = str(data.get("date") or "")
rver = str(remote.get("version") or "")
rdate = str(remote.get("date") or "")
# 版本只与 ~/RRPP 本地文件比对(回退文件仅用于读取,不参与更新判定) # 版本只与 ~/RRPP 本地文件比对(回退文件仅用于读取,不参与更新判定)
local = _USER_DIR / f"{name}.json" local = _USER_DIR / f"{name}.json"
lver = _pac_read_version(local)[0] if local.is_file() else "" lver = _pac_read_version(local)[0] if local.is_file() else ""
if rver and rver > lver: if rver:
try: if rver > lver:
ver, date = _pac_download(base, name) _pac_write(name, data)
log(f"PAC 数据已更新: {name}.json {ver or rver} ({date or rdate})") log(f"PAC 数据已更新: {name}.json {rver} ({rdate})")
updated += 1 updated += 1
except Exception as e: # 否则已是最新,跳过
log(f"PAC 数据 {name}.json 更新失败,使用本地副本: {e}") else:
if updated == 0 and (_USER_DIR / "pac_domains.json").is_file(): # 远端缺版本号:本地没有 -> 兜底下载;本地有 -> 按内容比对
log("PAC 数据已是最新") new_bytes = json.dumps(data, ensure_ascii=False).encode("utf-8")
if local.is_file() and local.read_bytes() == new_bytes:
continue
_pac_write(name, data)
log(f"PAC 数据已下载: {name}.json 无版本号 ({rdate})")
updated += 1
except Exception as e:
log(f"PAC 数据 {name}.json 更新失败,使用本地副本: {e}")
failed += 1
if updated == 0 and failed == 0 and (_USER_DIR / "pac_domains.json").is_file():
log("PAC 数据已是最新")
# 节点配置在线更新:地址独立于 PAC,按内容比对,仅变化时原子覆盖 # 节点配置在线更新:地址独立于 PAC,按内容比对,仅变化时原子覆盖
nurl = (nodes_url or str(_config_val("nodes_url", "") or "")).strip() nurl = (nodes_url or str(_config_val("nodes_url", "") or "")).strip()
if not nurl: if not nurl: