diff --git a/src/base/Proxy_Ping0_Labeler.cpp b/src/base/Proxy_Ping0_Labeler.cpp index 838c4bb..5ff3d06 100644 --- a/src/base/Proxy_Ping0_Labeler.cpp +++ b/src/base/Proxy_Ping0_Labeler.cpp @@ -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 #include @@ -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 +struct Public_Ip { + std::optional ip; + std::optional expired_ip; + std::optional ip_error; + std::optional 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 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 ipv4; - std::optional ipv6; - std::optional expired_ipv4; - std::optional expired_ipv6; - std::optional ipv4_error; - std::optional ipv6_error; - std::optional ipv4_cached_at_utc; - std::optional ipv6_cached_at_utc; + Public_Ip ipv4; + Public_Ip 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& 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 usable_ipv4(const Public_Ip_Cache& cache) { - return cache.ipv4 ? cache.ipv4 : cache.expired_ipv4; -} -std::optional 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 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 load_node_ping0_result(const Node_Route& route, const fs::path& ip_cache_dir, const fs::path& html_cache_dir, std::optional 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 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); diff --git a/src/base/config.h b/src/base/config.h index 54f6ece..6f70f09 100644 --- a/src/base/config.h +++ b/src/base/config.h @@ -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;