重构:模块化 RRPP Lite 并更新入口
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
"""PAC 路由引擎使用的纯算法,不依赖文件、网络或 Qt。"""
|
||||
|
||||
import ipaddress
|
||||
import re
|
||||
|
||||
|
||||
def merge_ip_ranges(cidrs, version):
|
||||
"""将指定 IP 版本的 CIDR 合并为整数闭区间,供二分查找。"""
|
||||
ranges = []
|
||||
for cidr in cidrs:
|
||||
network = ipaddress.ip_network(str(cidr).strip(), strict=False)
|
||||
if network.version == version:
|
||||
ranges.append((int(network.network_address), int(network.broadcast_address)))
|
||||
ranges.sort()
|
||||
merged = []
|
||||
for start, end in ranges:
|
||||
if merged and start <= merged[-1][1] + 1:
|
||||
if end > merged[-1][1]:
|
||||
merged[-1] = (merged[-1][0], end)
|
||||
else:
|
||||
merged.append((start, end))
|
||||
return merged
|
||||
|
||||
|
||||
def build_suffix_trie(suffixes):
|
||||
"""按反向域名标签建立 Trie,适合大规模后缀规则的 O(标签数) 匹配。"""
|
||||
root = {}
|
||||
for suffix in suffixes:
|
||||
node = root
|
||||
for label in reversed(suffix.split(".")):
|
||||
node = node.setdefault(label, {})
|
||||
node[""] = True
|
||||
return root
|
||||
|
||||
|
||||
def suffix_trie_matches(host: str, trie) -> bool:
|
||||
"""判断主机名是否命中一个后缀 Trie。"""
|
||||
node = trie
|
||||
for label in reversed(host.rstrip(".").lower().split(".")):
|
||||
node = node.get(label)
|
||||
if node is None:
|
||||
return False
|
||||
if node.get(""):
|
||||
return True
|
||||
return bool(node and node.get(""))
|
||||
|
||||
|
||||
def parse_domain_rules(raw_rules, seed_suffixes=()):
|
||||
"""解析后缀、``full:`` 与 ``regexp:`` 三种 PAC 域名规则。
|
||||
|
||||
返回 ``(suffixes, exact, regexes, invalid_regex_count)``。调用方决定
|
||||
这些规则是“强制代理”还是“明确直连”,从而避免解析层携带业务策略。
|
||||
"""
|
||||
suffixes = set(seed_suffixes)
|
||||
exact = set()
|
||||
regexes = []
|
||||
invalid_regexes = 0
|
||||
for raw in raw_rules or ():
|
||||
raw_rule = str(raw).strip()
|
||||
rule = raw_rule.lower()
|
||||
if not raw_rule:
|
||||
continue
|
||||
if rule.startswith("full:"):
|
||||
host = rule[len("full:"):].rstrip(".")
|
||||
if host:
|
||||
exact.add(host)
|
||||
continue
|
||||
if rule.startswith("regexp:"):
|
||||
pattern = raw_rule[len("regexp:"):]
|
||||
if not pattern:
|
||||
invalid_regexes += 1
|
||||
continue
|
||||
try:
|
||||
regexes.append(re.compile(pattern, re.IGNORECASE))
|
||||
except re.error:
|
||||
invalid_regexes += 1
|
||||
continue
|
||||
suffix = rule.lstrip("*.").rstrip(".")
|
||||
if suffix:
|
||||
suffixes.add(suffix)
|
||||
return suffixes, frozenset(exact), tuple(regexes), invalid_regexes
|
||||
Reference in New Issue
Block a user