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