规则更新

This commit is contained in:
2026-08-12 11:35:38 +08:00
parent 4e73e1edd7
commit ffc885b86d
2 changed files with 74 additions and 94 deletions
+74 -87
View File
@@ -4,7 +4,7 @@
#include "Proxy_Ping0_Labeler.h"
#include "Async_Blocking.h"
#include "Ping0_Html_Parser.h"
#include "config.h"
#include "Public_Ip_Config.h"
#include "export.h"
#include <algorithm>
#include <array>
@@ -39,15 +39,47 @@ struct Node_Route {
std::string username;
std::string proxy_name;
};
std::string query_public_ip_by_user(std::string_view username, uint16_t mixed_port, std::string_view host);
template <int cache_ttl_seconds, bool radical>
struct Public_Ip {
std::optional<std::string> ip;
std::optional<std::string> expired_ip;
std::optional<std::string> ip_error;
std::optional<std::chrono::system_clock::time_point> ip_cached_at_utc;
bool is_expired() const {
if (cache_ttl_seconds <= 0) {
return false;
}
if (!ip_cached_at_utc) {
return true;
}
return std::chrono::system_clock::now() - *ip_cached_at_utc >= std::chrono::seconds(cache_ttl_seconds);
}
bool should_refresh() const {
const bool expired = is_expired();
return radical ? expired : expired && !ip.has_value();
}
std::optional<std::string> get_ip() const {
return ip ? ip : expired_ip;
}
void refresh(std::string_view username, uint16_t mixed_port, std::string_view host) {
const auto old_ip = get_ip();
ip.reset();
ip_error.reset();
ip_cached_at_utc = std::chrono::system_clock::now();
try {
ip = query_public_ip_by_user(username, mixed_port, host);
expired_ip.reset();
}
catch (const std::exception& error) {
expired_ip = old_ip;
ip_error = error_text_to_utf8(error.what());
}
}
};
struct Public_Ip_Cache {
std::optional<std::string> ipv4;
std::optional<std::string> ipv6;
std::optional<std::string> expired_ipv4;
std::optional<std::string> expired_ipv6;
std::optional<std::string> ipv4_error;
std::optional<std::string> ipv6_error;
std::optional<std::chrono::system_clock::time_point> ipv4_cached_at_utc;
std::optional<std::chrono::system_clock::time_point> ipv6_cached_at_utc;
Public_Ip<public_ipv4_cache_ttl_seconds, radical_ipv4> ipv4;
Public_Ip<public_ipv6_cache_ttl_seconds, radical_ipv6> ipv6;
};
struct Node_Ping0_Result {
std::string name;
@@ -251,20 +283,20 @@ Public_Ip_Cache load_cached_public_ips(const fs::path& path) {
return result;
}
const auto cache = load_yaml_file(path);
result.ipv4 = read_optional_string(cache, "public_ipv4");
if (!result.ipv4) {
result.ipv4 = read_optional_string(cache, "public_ip");
result.ipv4.ip = read_optional_string(cache, "public_ipv4");
if (!result.ipv4.ip) {
result.ipv4.ip = read_optional_string(cache, "public_ip");
}
result.ipv6 = read_optional_string(cache, "public_ipv6");
result.expired_ipv4 = read_optional_string(cache, "expired_public_ipv4");
result.expired_ipv6 = read_optional_string(cache, "expired_public_ipv6");
result.ipv4_error = read_optional_string(cache, "public_ipv4_error");
result.ipv6_error = read_optional_string(cache, "public_ipv6_error");
result.ipv6.ip = read_optional_string(cache, "public_ipv6");
result.ipv4.expired_ip = read_optional_string(cache, "expired_public_ipv4");
result.ipv6.expired_ip = read_optional_string(cache, "expired_public_ipv6");
result.ipv4.ip_error = read_optional_string(cache, "public_ipv4_error");
result.ipv6.ip_error = read_optional_string(cache, "public_ipv6_error");
if (const auto cached_at = read_optional_string(cache, "public_ipv4_cached_at_utc")) {
result.ipv4_cached_at_utc = parse_utc_time(*cached_at);
result.ipv4.ip_cached_at_utc = parse_utc_time(*cached_at);
}
if (const auto cached_at = read_optional_string(cache, "public_ipv6_cached_at_utc")) {
result.ipv6_cached_at_utc = parse_utc_time(*cached_at);
result.ipv6.ip_cached_at_utc = parse_utc_time(*cached_at);
}
return result;
}
@@ -296,30 +328,30 @@ void save_public_ip_cache(const fs::path& path, const Node_Route& route, const P
node["proxy_name"] = route.proxy_name;
node["username"] = route.username;
node["mixed_port"] = mixed_port;
if (cache.ipv4) {
node["public_ip"] = *cache.ipv4;
node["public_ipv4"] = *cache.ipv4;
if (cache.ipv4.ip) {
node["public_ip"] = *cache.ipv4.ip;
node["public_ipv4"] = *cache.ipv4.ip;
}
if (cache.ipv6) {
node["public_ipv6"] = *cache.ipv6;
if (cache.ipv6.ip) {
node["public_ipv6"] = *cache.ipv6.ip;
}
if (cache.expired_ipv4) {
node["expired_public_ipv4"] = *cache.expired_ipv4;
if (cache.ipv4.expired_ip) {
node["expired_public_ipv4"] = *cache.ipv4.expired_ip;
}
if (cache.expired_ipv6) {
node["expired_public_ipv6"] = *cache.expired_ipv6;
if (cache.ipv6.expired_ip) {
node["expired_public_ipv6"] = *cache.ipv6.expired_ip;
}
if (cache.ipv4_error) {
node["public_ipv4_error"] = *cache.ipv4_error;
if (cache.ipv4.ip_error) {
node["public_ipv4_error"] = *cache.ipv4.ip_error;
}
if (cache.ipv6_error) {
node["public_ipv6_error"] = *cache.ipv6_error;
if (cache.ipv6.ip_error) {
node["public_ipv6_error"] = *cache.ipv6.ip_error;
}
if (cache.ipv4_cached_at_utc) {
node["public_ipv4_cached_at_utc"] = make_utc_time(*cache.ipv4_cached_at_utc);
if (cache.ipv4.ip_cached_at_utc) {
node["public_ipv4_cached_at_utc"] = make_utc_time(*cache.ipv4.ip_cached_at_utc);
}
if (cache.ipv6_cached_at_utc) {
node["public_ipv6_cached_at_utc"] = make_utc_time(*cache.ipv6_cached_at_utc);
if (cache.ipv6.ip_cached_at_utc) {
node["public_ipv6_cached_at_utc"] = make_utc_time(*cache.ipv6.ip_cached_at_utc);
}
node["ipv4_source"] = source_url(ipv4_query_url_host);
node["ipv6_source"] = source_url(ipv6_query_url_host);
@@ -331,65 +363,20 @@ void save_public_ip_cache(const fs::path& path, const Node_Route& route, const P
}
write_file_atomic(path, std::string_view(emitter.c_str(), emitter.size()));
}
bool public_ip_cache_expired(const std::optional<std::chrono::system_clock::time_point>& cached_at_utc, int ttl_seconds) {
if (ttl_seconds <= 0) {
return false;
}
if (!cached_at_utc) {
return true;
}
return std::chrono::system_clock::now() - *cached_at_utc >= std::chrono::seconds(ttl_seconds);
}
void refresh_public_ipv4(Public_Ip_Cache& cache, std::string_view username, uint16_t mixed_port) {
const auto old_ipv4 = cache.ipv4 ? cache.ipv4 : cache.expired_ipv4;
cache.ipv4.reset();
cache.ipv4_error.reset();
cache.ipv4_cached_at_utc = std::chrono::system_clock::now();
try {
cache.ipv4 = query_public_ip_by_user(username, mixed_port, ipv4_query_url_host);
cache.expired_ipv4.reset();
}
catch (const std::exception& error) {
cache.expired_ipv4 = old_ipv4;
cache.ipv4_error = error_text_to_utf8(error.what());
}
}
void refresh_public_ipv6(Public_Ip_Cache& cache, std::string_view username, uint16_t mixed_port) {
const auto old_ipv6 = cache.ipv6 ? cache.ipv6 : cache.expired_ipv6;
cache.ipv6.reset();
cache.ipv6_error.reset();
cache.ipv6_cached_at_utc = std::chrono::system_clock::now();
try {
cache.ipv6 = query_public_ip_by_user(username, mixed_port, ipv6_query_url_host);
cache.expired_ipv6.reset();
}
catch (const std::exception& error) {
cache.expired_ipv6 = old_ipv6;
cache.ipv6_error = error_text_to_utf8(error.what());
}
}
std::optional<std::string> usable_ipv4(const Public_Ip_Cache& cache) {
return cache.ipv4 ? cache.ipv4 : cache.expired_ipv4;
}
std::optional<std::string> usable_ipv6(const Public_Ip_Cache& cache) {
return cache.ipv6 ? cache.ipv6 : cache.expired_ipv6;
}
Public_Ip_Cache get_public_ips(const Node_Route& route, const fs::path& cache_dir, std::optional<uint16_t> mixed_port) {
const auto cache_path = make_ip_cache_path(cache_dir, route.proxy_name);
std::lock_guard lock(public_ip_cache_lock(cache_path));
Public_Ip_Cache cache = load_cached_public_ips(cache_path);
const bool ipv4_expired = public_ip_cache_expired(cache.ipv4_cached_at_utc, public_ipv4_cache_ttl_seconds);
const bool ipv6_expired = public_ip_cache_expired(cache.ipv6_cached_at_utc, public_ipv6_cache_ttl_seconds);
bool changed = false;
if (!mixed_port) {
return cache;
}
if (radical_ipv4 ? ipv4_expired : ipv4_expired && !cache.ipv4.has_value()) {
refresh_public_ipv4(cache, route.username, *mixed_port);
if (cache.ipv4.should_refresh()) {
cache.ipv4.refresh(route.username, *mixed_port, ipv4_query_url_host);
changed = true;
}
if (radical_ipv6 ? ipv6_expired : ipv6_expired && !cache.ipv6.has_value()) {
refresh_public_ipv6(cache, route.username, *mixed_port);
if (cache.ipv6.should_refresh()) {
cache.ipv6.refresh(route.username, *mixed_port, ipv6_query_url_host);
changed = true;
}
if (changed) {
@@ -538,7 +525,7 @@ void print_ping0_info(const Node_Route& route, const Node_Ping0_Result& result)
}
std::optional<Node_Ping0_Result> load_node_ping0_result(const Node_Route& route, const fs::path& ip_cache_dir, const fs::path& html_cache_dir, std::optional<uint16_t> mixed_port) {
const auto public_ips = get_public_ips(route, ip_cache_dir, mixed_port);
const auto public_ipv4 = usable_ipv4(public_ips);
const auto public_ipv4 = public_ips.ipv4.get_ip();
if (!public_ipv4) {
std::cerr << std::format("Ping0 标注跳过:节点 {} 没有 IPv4 出口缓存\n", route.proxy_name);
return std::nullopt;
@@ -549,7 +536,7 @@ std::optional<Node_Ping0_Result> load_node_ping0_result(const Node_Route& route,
return std::nullopt;
}
auto info = Ping0::parse_file(*html_path);
return Node_Ping0_Result{route.proxy_name, *public_ipv4, usable_ipv6(public_ips), make_ip_cache_path(ip_cache_dir, route.proxy_name), *html_path, std::move(info), route.index, std::nullopt};
return Node_Ping0_Result{route.proxy_name, *public_ipv4, public_ips.ipv6.get_ip(), make_ip_cache_path(ip_cache_dir, route.proxy_name), *html_path, std::move(info), route.index, std::nullopt};
}
void record_ai_node_info(Node_Ping0_Result result, const fs::path& node_state_dir) {
const auto ai_score = ai_scene_score(result.info);
-7
View File
@@ -1,8 +1 @@
#pragma once
// 出口 IPv4 缓存有效期,单位秒;0 表示永不过期。
inline constexpr int public_ipv4_cache_ttl_seconds = 7 * 24 * 60 * 60;
// 出口 IPv6 缓存有效期,单位秒;0 表示永不过期。
inline constexpr int public_ipv6_cache_ttl_seconds = 7 * 24 * 60 * 60;
// true 表示对应缓存过期就重查;false 表示过期且缺少对应 IP 才重查。
inline constexpr bool radical_ipv4 = true;
inline constexpr bool radical_ipv6 = true;