diff --git a/base/pref.example.ini b/base/pref.example.ini index 1b1b55c0a1..34c452dfc9 100644 --- a/base/pref.example.ini +++ b/base/pref.example.ini @@ -201,9 +201,11 @@ ruleset=!!import:snippets/rulesets.txt ;Rule with "[]" prefix will be added directly. ;custom_proxy_group=Proxy`select`.*`[]AUTO`[]DIRECT`.* +;custom_proxy_group=ProxyWithMaxFailed`select`.*`!!MAX_FAILED_TIMES=5`[]AUTO`[]DIRECT`.* ;custom_proxy_group=UrlTest`url-test`.*`http://www.gstatic.com/generate_204`300,5,100 ;custom_proxy_group=FallBack`fallback`.*`http://www.gstatic.com/generate_204`300,5 ;custom_proxy_group=LoadBalance`load-balance`.*`http://www.gstatic.com/generate_204`300,,100 +;custom_proxy_group=LoadBalanceSticky`load-balance`.*`!!STRATEGY=sticky-sessions`!!MAX_FAILED_TIMES=5`http://www.gstatic.com/generate_204`300,,100 ;custom_proxy_group=SSID`ssid`default_group`celluar=group0,ssid1=group1,ssid2=group2 ;custom_proxy_group=g1`select`!!GROUPID=0 diff --git a/base/pref.example.yml b/base/pref.example.yml index 5e27275043..92950ba8ca 100644 --- a/base/pref.example.yml +++ b/base/pref.example.yml @@ -95,7 +95,9 @@ rulesets: proxy_groups: custom_proxy_group: # - {name: UrlTest, type: url-test, rule: [".*"], url: http://www.gstatic.com/generate_204, interval: 300, tolerance: 100, timeout: 5} +# - {name: LoadBalanceSticky, type: load-balance, rule: [".*"], url: http://www.gstatic.com/generate_204, interval: 300, timeout: 5, tolerance: 100, max-failed-times: 5, strategy: sticky-sessions} # - {name: Proxy, type: select, rule: [".*"]} +# - {name: ProxyWithMaxFailed, type: select, rule: [".*"], max-failed-times: 5} # - {name: group1, type: select, rule: ["!!GROUPID=0"]} # - {name: v2ray, type: select, rule: ["!!GROUP=V2RayProvider"]} # - {import: snippets/groups_forcerule.txt} diff --git a/src/config/binding.h b/src/config/binding.h index e069869d50..60d5cfa774 100644 --- a/src/config/binding.h +++ b/src/config/binding.h @@ -47,6 +47,9 @@ namespace toml case "round-robin"_hash: conf.Strategy = BalanceStrategy::RoundRobin; break; + case "sticky-sessions"_hash: + conf.Strategy = BalanceStrategy::StickySessions; + break; } if(v.contains("persistent")) conf.Persistent = find_or(v, "persistent", conf.Persistent.get()); @@ -80,6 +83,7 @@ namespace toml conf.Timeout = find_or(v, "timeout", 5); conf.Proxies = find_or(v, "rule", {}); conf.UsingProvider = find_or(v, "use", {}); + conf.MaxFailedTimes = find_or(v, "max_failed_times", 5); if(conf.Proxies.empty() && conf.UsingProvider.empty()) throw serialization_error(format_error("Proxy Group must contains at least one of proxy match rule or provider!", v.location(), "here"), v.location()); if(v.contains("disable-udp")) @@ -254,6 +258,26 @@ namespace INIBinding conf.UsingProvider.reserve(conf.UsingProvider.size() + list.size()); std::move(list.begin(), list.end(), std::back_inserter(conf.UsingProvider)); } + else if(startsWith(vArray[i], "!!MAX_FAILED_TIMES=")) + { + conf.MaxFailedTimes = to_int(vArray[i].substr(19), 0); + } + else if(startsWith(vArray[i], "!!STRATEGY=")) + { + std::string strategy = vArray[i].substr(11); + switch(hash_(strategy)) + { + case "consistent-hashing"_hash: + conf.Strategy = BalanceStrategy::ConsistentHashing; + break; + case "round-robin"_hash: + conf.Strategy = BalanceStrategy::RoundRobin; + break; + case "sticky-sessions"_hash: + conf.Strategy = BalanceStrategy::StickySessions; + break; + } + } else conf.Proxies.emplace_back(std::move(vArray[i])); } diff --git a/src/config/proxygroup.h b/src/config/proxygroup.h index 07dbddc182..12861bf60a 100644 --- a/src/config/proxygroup.h +++ b/src/config/proxygroup.h @@ -17,7 +17,8 @@ enum class ProxyGroupType enum class BalanceStrategy { ConsistentHashing, - RoundRobin + RoundRobin, + StickySessions }; struct ProxyGroupConfig @@ -30,6 +31,7 @@ struct ProxyGroupConfig Integer Interval = 0; Integer Timeout = 0; Integer Tolerance = 0; + Integer MaxFailedTimes = 5; BalanceStrategy Strategy = BalanceStrategy::ConsistentHashing; Boolean Lazy; Boolean DisableUdp; @@ -57,6 +59,7 @@ struct ProxyGroupConfig { case BalanceStrategy::ConsistentHashing: return "consistent-hashing"; case BalanceStrategy::RoundRobin: return "round-robin"; + case BalanceStrategy::StickySessions: return "sticky-sessions"; } return ""; } diff --git a/src/generator/config/subexport.cpp b/src/generator/config/subexport.cpp index 2cb2281516..2807b28979 100644 --- a/src/generator/config/subexport.cpp +++ b/src/generator/config/subexport.cpp @@ -781,6 +781,8 @@ void proxyToClash(std::vector &nodes, YAML::Node &yamlnode, const ProxyGr if(!x.DisableUdp.is_undef()) singlegroup["disable-udp"] = x.DisableUdp.get(); + singlegroup["max-failed-times"] = x.MaxFailedTimes; + for(const auto& y : x.Proxies) groupGenerate(y, nodelist, filtered_nodelist, true, ext); diff --git a/src/handler/settings.cpp b/src/handler/settings.cpp index a90bec7a8b..ac4ea20ad3 100644 --- a/src/handler/settings.cpp +++ b/src/handler/settings.cpp @@ -182,6 +182,7 @@ void readGroup(YAML::Node node, string_array &dest, bool scope_limit = true) continue; } std::string url = "http://www.gstatic.com/generate_204", interval = "300", tolerance, timeout; + std::string max_failed_times, strategy; object["name"] >>= name; object["type"] >>= type; tempArray.emplace_back(name); @@ -190,8 +191,14 @@ void readGroup(YAML::Node node, string_array &dest, bool scope_limit = true) object["interval"] >>= interval; object["tolerance"] >>= tolerance; object["timeout"] >>= timeout; + object["max_failed_times"] >>= max_failed_times; + object["strategy"] >>= strategy; for(std::size_t j = 0; j < object["rule"].size(); j++) tempArray.emplace_back(safe_as(object["rule"][j])); + if(!max_failed_times.empty()) + tempArray.emplace_back("!!MAX_FAILED_TIMES=" + max_failed_times); + if(!strategy.empty()) + tempArray.emplace_back("!!STRATEGY=" + strategy); switch(hash_(type)) { case "select"_hash: