Enhancements

Add basic support for generating sing-box configs.
Use cpp-httplib as web server.
Optimize codes.
This commit is contained in:
Tindy X committed 2023-11-07 22:12:01 +08:00
1 parent f99748b126
commit bbcb6434e1
32 files changed
+10286 -234

No files matched your search

+115 -15
View File
@@ -5,6 +5,7 @@
#include "../../utils/network.h"
#include "../../utils/regexp.h"
#include "../../utils/string.h"
#include "../../utils/rapidjson_extra.h"
#include "subexport.h"
/// rule type lists
@@ -28,7 +29,7 @@ std::string convertRuleset(const std::string &content, int type)
if(regFind(content, "^payload:\\r?\\n")) /// Clash
{
output = regReplace(regReplace(content, "payload:\\r?\\n", "", true), "\\s?^\\s*-\\s+('|\"?)(.*)\\1$", "\n$2", true);
output = regReplace(regReplace(content, "payload:\\r?\\n", "", true), R"(\s?^\s*-\s+('|"?)(.*)\1$)", "\n$2", true);
if(type == RULESET_CLASH_CLASSICAL) /// classical type
return output;
std::stringstream ss;
@@ -51,8 +52,8 @@ std::string convertRuleset(const std::string &content, int type)
if(!strLine.empty() && (strLine[0] != ';' && strLine[0] != '#' && !(lineSize >= 2 && strLine[0] == '/' && strLine[1] == '/')))
{
pos = strLine.find("/");
if(pos != strLine.npos) /// ipcidr
pos = strLine.find('/');
if(pos != std::string::npos) /// ipcidr
{
if(isIPv4(strLine.substr(0, pos)))
output += "IP-CIDR,";
@@ -143,7 +144,7 @@ void rulesetToClash(YAML::Node &base_rule, std::vector<RulesetContent> &ruleset_
lineSize = strLine.size();
if(!lineSize || strLine[0] == ';' || strLine[0] == '#' || (lineSize >= 2 && strLine[0] == '/' && strLine[1] == '/')) //empty lines and comments are ignored
continue;
if(std::none_of(ClashRuleTypes.begin(), ClashRuleTypes.end(), [strLine](std::string type){return startsWith(strLine, type);}))
if(std::none_of(ClashRuleTypes.begin(), ClashRuleTypes.end(), [strLine](const std::string& type){return startsWith(strLine, type);}))
continue;
if(strFind(strLine, "//"))
{
@@ -218,7 +219,7 @@ std::string rulesetToClashStr(YAML::Node &base_rule, std::vector<RulesetContent>
lineSize = strLine.size();
if(!lineSize || strLine[0] == ';' || strLine[0] == '#' || (lineSize >= 2 && strLine[0] == '/' && strLine[1] == '/')) //empty lines and comments are ignored
continue;
if(std::none_of(ClashRuleTypes.begin(), ClashRuleTypes.end(), [strLine](std::string type){ return startsWith(strLine, type); }))
if(std::none_of(ClashRuleTypes.begin(), ClashRuleTypes.end(), [strLine](const std::string& type){ return startsWith(strLine, type); }))
continue;
if(strFind(strLine, "//"))
{
@@ -235,7 +236,7 @@ std::string rulesetToClashStr(YAML::Node &base_rule, std::vector<RulesetContent>
return output_content;
}
void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_content_array, int surge_ver, bool overwrite_original_rules, std::string remote_path_prefix)
void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_content_array, int surge_ver, bool overwrite_original_rules, const std::string &remote_path_prefix)
{
string_array allRules;
std::string rule_group, rule_path, rule_path_typed, retrieved_rules, strLine;
@@ -268,6 +269,8 @@ void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_c
case -4:
base_rule.erase_section("Remote Rule");
break;
default:
break;
}
}
@@ -313,7 +316,7 @@ void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_c
}
if(fileExist(rule_path))
{
if(surge_ver > 2 && remote_path_prefix.size())
if(surge_ver > 2 && !remote_path_prefix.empty())
{
strLine = "RULE-SET," + remote_path_prefix + "/getruleset?type=1&url=" + urlSafeBase64Encode(rule_path_typed) + "," + rule_group;
if(x.update_interval)
@@ -321,14 +324,14 @@ void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_c
allRules.emplace_back(std::move(strLine));
continue;
}
else if(surge_ver == -1 && remote_path_prefix.size())
else if(surge_ver == -1 && !remote_path_prefix.empty())
{
strLine = remote_path_prefix + "/getruleset?type=2&url=" + urlSafeBase64Encode(rule_path_typed) + "&group=" + urlSafeBase64Encode(rule_group);
strLine += ", tag=" + rule_group + ", enabled=true";
base_rule.set("filter_remote", "{NONAME}", strLine);
continue;
}
else if(surge_ver == -4 && remote_path_prefix.size())
else if(surge_ver == -4 && !remote_path_prefix.empty())
{
strLine = remote_path_prefix + "/getruleset?type=1&url=" + urlSafeBase64Encode(rule_path_typed) + "," + rule_group;
base_rule.set("Remote Rule", "{NONAME}", strLine);
@@ -341,7 +344,7 @@ void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_c
{
if(x.rule_type != RULESET_SURGE)
{
if(remote_path_prefix.size())
if(!remote_path_prefix.empty())
strLine = "RULE-SET," + remote_path_prefix + "/getruleset?type=1&url=" + urlSafeBase64Encode(rule_path_typed) + "," + rule_group;
else
continue;
@@ -355,7 +358,7 @@ void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_c
allRules.emplace_back(std::move(strLine));
continue;
}
else if(surge_ver == -1 && remote_path_prefix.size())
else if(surge_ver == -1 && !remote_path_prefix.empty())
{
strLine = remote_path_prefix + "/getruleset?type=2&url=" + urlSafeBase64Encode(rule_path_typed) + "&group=" + urlSafeBase64Encode(rule_group);
strLine += ", tag=" + rule_group + ", enabled=true";
@@ -401,22 +404,22 @@ void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_c
continue;
[[fallthrough]];
case -1:
if(!std::any_of(QuanXRuleTypes.begin(), QuanXRuleTypes.end(), [strLine](std::string type){return startsWith(strLine, type);}))
if(!std::any_of(QuanXRuleTypes.begin(), QuanXRuleTypes.end(), [strLine](const std::string& type){return startsWith(strLine, type);}))
continue;
break;
case -3:
if(!std::any_of(SurfRuleTypes.begin(), SurfRuleTypes.end(), [strLine](std::string type){return startsWith(strLine, type);}))
if(!std::any_of(SurfRuleTypes.begin(), SurfRuleTypes.end(), [strLine](const std::string& type){return startsWith(strLine, type);}))
continue;
break;
default:
if(surge_ver > 2)
{
if(!std::any_of(SurgeRuleTypes.begin(), SurgeRuleTypes.end(), [strLine](std::string type){return startsWith(strLine, type);}))
if(!std::any_of(SurgeRuleTypes.begin(), SurgeRuleTypes.end(), [strLine](const std::string& type){return startsWith(strLine, type);}))
continue;
}
else
{
if(!std::any_of(Surge2RuleTypes.begin(), Surge2RuleTypes.end(), [strLine](std::string type){return startsWith(strLine, type);}))
if(!std::any_of(Surge2RuleTypes.begin(), Surge2RuleTypes.end(), [strLine](const std::string& type){return startsWith(strLine, type);}))
continue;
}
}
@@ -453,3 +456,100 @@ void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_c
base_rule.set("{NONAME}", x);
}
}
static rapidjson::Value transformRuleToSingBox(const std::string& rule, rapidjson::MemoryPoolAllocator<>& allocator)
{
std::string type, value, group, option;
regGetMatch(rule, "^(.*?),(.*?)(?:,(.*?))?(,.*)?$", 5, nullptr, &type, &value, &group, &option);
rapidjson::Value rule_obj(rapidjson::kObjectType);
type = replaceAllDistinct(toLower(type), "-", "_");
type = replaceAllDistinct(type, "ip_cidr6", "ip_cidr");
if (type == "match" || type == "final") {
rule_obj.AddMember("outbound", rapidjson::Value(value.c_str(), allocator), allocator);
} else {
rule_obj.AddMember(rapidjson::Value(type.c_str(), allocator), rapidjson::Value(value.c_str(), allocator), allocator);
rule_obj.AddMember("outbound", rapidjson::Value(group.c_str(), allocator), allocator);
}
return rule_obj;
}
void rulesetToSingBox(rapidjson::Document &base_rule, std::vector<RulesetContent> &ruleset_content_array, bool overwrite_original_rules)
{
std::string rule_group, retrieved_rules, strLine, final;
std::stringstream strStrm;
size_t total_rules = 0;
rapidjson::MemoryPoolAllocator<>& allocator = base_rule.GetAllocator();
rapidjson::Value rules(rapidjson::kArrayType);
if (!overwrite_original_rules)
{
if (base_rule.HasMember("route") && base_rule["route"].HasMember("rules") && base_rule["route"]["rules"].IsArray())
rules.Swap(base_rule["route"]["rules"]);
}
for(RulesetContent &x : ruleset_content_array)
{
if(global.maxAllowedRules && total_rules > global.maxAllowedRules)
break;
rule_group = x.rule_group;
retrieved_rules = x.rule_content.get();
if(retrieved_rules.empty())
{
writeLog(0, "Failed to fetch ruleset or ruleset is empty: '" + x.rule_path + "'!", LOG_LEVEL_WARNING);
continue;
}
if(startsWith(retrieved_rules, "[]"))
{
strLine = retrieved_rules.substr(2);
if(startsWith(strLine, "FINAL") || startsWith(strLine, "MATCH"))
{
final = rule_group;
continue;
}
strLine += "," + rule_group;
if(count_least(strLine, ',', 3))
strLine = regReplace(strLine, "^(.*?,.*?)(,.*)(,.*)$", "$1$3$2");
rules.PushBack(transformRuleToSingBox(strLine, allocator), allocator);
total_rules++;
continue;
}
retrieved_rules = convertRuleset(retrieved_rules, x.rule_type);
char delimiter = getLineBreak(retrieved_rules);
strStrm.clear();
strStrm<<retrieved_rules;
std::string::size_type lineSize;
while(getline(strStrm, strLine, delimiter))
{
if(global.maxAllowedRules && total_rules > global.maxAllowedRules)
break;
strLine = trimWhitespace(strLine, true, true); //remove whitespaces
lineSize = strLine.size();
if(!lineSize || strLine[0] == ';' || strLine[0] == '#' || (lineSize >= 2 && strLine[0] == '/' && strLine[1] == '/')) //empty lines and comments are ignored
continue;
if(std::none_of(ClashRuleTypes.begin(), ClashRuleTypes.end(), [strLine](const std::string& type){return startsWith(strLine, type);}))
continue;
if(strFind(strLine, "//"))
{
strLine.erase(strLine.find("//"));
strLine = trimWhitespace(strLine);
}
strLine += "," + rule_group;
if(count_least(strLine, ',', 3))
strLine = regReplace(strLine, "^(.*?,.*?)(,.*)(,.*)$", "$1$3$2");
rules.PushBack(transformRuleToSingBox(strLine, allocator), allocator);
}
}
if (!base_rule.HasMember("route"))
base_rule.AddMember("route", rapidjson::Value(rapidjson::kObjectType), allocator);
if (!base_rule["route"].HasMember("rules"))
base_rule["route"].AddMember("rules", rapidjson::Value(rapidjson::kArrayType), allocator);
base_rule["route"]["rules"].Swap(rules);
if (!base_rule["route"].HasMember("final"))
base_rule["route"].AddMember("final", rapidjson::Value(final.c_str(), allocator), allocator);
else
base_rule["route"]["final"].SetString(final.c_str(), allocator);
}
+3 -1
View File
@@ -6,6 +6,7 @@
#include <future>
#include <yaml-cpp/yaml.h>
#include <rapidjson/document.h>
#include "../../utils/ini_reader/ini_reader.h"
@@ -31,6 +32,7 @@ struct RulesetContent
std::string convertRuleset(const std::string &content, int type);
void rulesetToClash(YAML::Node &base_rule, std::vector<RulesetContent> &ruleset_content_array, bool overwrite_original_rules, bool new_field_name);
std::string rulesetToClashStr(YAML::Node &base_rule, std::vector<RulesetContent> &ruleset_content_array, bool overwrite_original_rules, bool new_field_name);
void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_content_array, int surge_ver, bool overwrite_original_rules, std::string remote_path_prefix);
void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_content_array, int surge_ver, bool overwrite_original_rules, const std::string& remote_path_prefix);
void rulesetToSingBox(rapidjson::Document &base_rule, std::vector<RulesetContent> &ruleset_content_array, bool overwrite_original_rules);
#endif // RULECONVERT_H_INCLUDED
+300 -1
View File
@@ -1817,7 +1817,6 @@ void proxyToMellow(std::vector<Proxy> &nodes, INIReader &ini, std::vector<Rulese
std::string proxyToLoon(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<RulesetContent> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext)
{
rapidjson::Document json;
INIReader ini;
std::string output_nodelist;
std::vector<Proxy> nodelist;
@@ -2042,3 +2041,303 @@ std::string proxyToLoon(std::vector<Proxy> &nodes, const std::string &base_conf,
return ini.to_string();
}
static std::string formatSingBoxInterval(Integer interval)
{
std::string result;
if(interval >= 3600)
{
result += std::to_string(interval / 3600) + "h";
interval %= 3600;
}
if(interval >= 60)
{
result += std::to_string(interval / 60) + "m";
interval %= 60;
}
if(interval > 0)
result += std::to_string(interval) + "s";
return result;
}
static rapidjson::Value buildV2RayTransport(const Proxy& proxy, rapidjson::MemoryPoolAllocator<>& allocator)
{
rapidjson::Value transport(rapidjson::kObjectType);
switch (hash_(proxy.TransferProtocol))
{
case "http"_hash:
{
if (!proxy.Host.empty())
transport.AddMember("host", rapidjson::StringRef(proxy.Host.c_str()), allocator);
[[fallthrough]];
}
case "ws"_hash:
{
transport.AddMember("type", rapidjson::StringRef(proxy.TransferProtocol.c_str()), allocator);
if (proxy.Path.empty())
transport.AddMember("path", "/", allocator);
else
transport.AddMember("path", rapidjson::StringRef(proxy.Path.c_str()), allocator);
rapidjson::Value headers(rapidjson::kObjectType);
if (!proxy.Host.empty())
headers.AddMember("Host", rapidjson::StringRef(proxy.Host.c_str()), allocator);
if (!proxy.Edge.empty())
headers.AddMember("Edge", rapidjson::StringRef(proxy.Edge.c_str()), allocator);
transport.AddMember("headers", headers, allocator);
break;
}
case "grpc"_hash:
{
transport.AddMember("type", "grpc", allocator);
if (!proxy.Path.empty())
transport.AddMember("service_name", rapidjson::StringRef(proxy.Path.c_str()), allocator);
break;
}
default:
break;
}
return transport;
}
void proxyToSingBox(std::vector<Proxy> &nodes, rapidjson::Document &json, std::vector<RulesetContent> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext) {
rapidjson::Document::AllocatorType &allocator = json.GetAllocator();
rapidjson::Value outbounds(rapidjson::kArrayType), route(rapidjson::kArrayType);
std::vector<Proxy> nodelist;
auto direct = buildObject(allocator, "type", "direct", "tag", "DIRECT");
outbounds.PushBack(direct, allocator);
auto reject = buildObject(allocator, "type", "block", "tag", "REJECT");
outbounds.PushBack(reject, allocator);
for (Proxy &x : nodes)
{
std::string type = getProxyTypeName(x.Type);
if (ext.append_proxy_type)
x.Remark = "[" + type + "] " + x.Remark;
tribool udp = ext.udp, tfo = ext.tfo, scv = ext.skip_cert_verify;
udp.define(x.UDP);
tfo.define(x.TCPFastOpen);
scv.define(x.AllowInsecure);
rapidjson::Value proxy(rapidjson::kObjectType);
switch (x.Type)
{
case ProxyType::Shadowsocks:
{
proxy.AddMember("type", "shadowsocks", allocator);
proxy.AddMember("tag", rapidjson::StringRef(x.Remark.c_str()), allocator);
proxy.AddMember("server", rapidjson::StringRef(x.Hostname.c_str()), allocator);
proxy.AddMember("server_port", x.Port, allocator);
proxy.AddMember("method", rapidjson::StringRef(x.EncryptMethod.c_str()), allocator);
proxy.AddMember("password", rapidjson::StringRef(x.Password.c_str()), allocator);
if(!x.Plugin.empty() && !x.PluginOption.empty())
{
proxy.AddMember("plugin", rapidjson::StringRef(x.Plugin.c_str()), allocator);
proxy.AddMember("plugin_opts", rapidjson::StringRef(x.PluginOption.c_str()), allocator);
}
break;
}
case ProxyType::ShadowsocksR:
{
proxy.AddMember("type", "shadowsocksr", allocator);
proxy.AddMember("tag", rapidjson::StringRef(x.Remark.c_str()), allocator);
proxy.AddMember("server", rapidjson::StringRef(x.Hostname.c_str()), allocator);
proxy.AddMember("server_port", x.Port, allocator);
proxy.AddMember("method", rapidjson::StringRef(x.EncryptMethod.c_str()), allocator);
proxy.AddMember("password", rapidjson::StringRef(x.Password.c_str()), allocator);
proxy.AddMember("protocol", rapidjson::StringRef(x.Protocol.c_str()), allocator);
proxy.AddMember("protocol_param", rapidjson::StringRef(x.ProtocolParam.c_str()), allocator);
proxy.AddMember("obfs", rapidjson::StringRef(x.OBFS.c_str()), allocator);
proxy.AddMember("obfs_param", rapidjson::StringRef(x.OBFSParam.c_str()), allocator);
break;
}
case ProxyType::VMess:
{
proxy.AddMember("type", "vmess", allocator);
proxy.AddMember("tag", rapidjson::StringRef(x.Remark.c_str()), allocator);
proxy.AddMember("server", rapidjson::StringRef(x.Hostname.c_str()), allocator);
proxy.AddMember("server_port", x.Port, allocator);
proxy.AddMember("uuid", rapidjson::StringRef(x.UserId.c_str()), allocator);
proxy.AddMember("alter_id", x.AlterId, allocator);
proxy.AddMember("cipher", rapidjson::StringRef(x.EncryptMethod.c_str()), allocator);
auto transport = buildV2RayTransport(x, allocator);
proxy.AddMember("transport", transport, allocator);
break;
}
case ProxyType::Trojan:
{
proxy.AddMember("type", "trojan", allocator);
proxy.AddMember("tag", rapidjson::StringRef(x.Remark.c_str()), allocator);
proxy.AddMember("server", rapidjson::StringRef(x.Hostname.c_str()), allocator);
proxy.AddMember("server_port", x.Port, allocator);
proxy.AddMember("password", rapidjson::StringRef(x.Password.c_str()), allocator);
auto transport = buildV2RayTransport(x, allocator);
proxy.AddMember("transport", transport, allocator);
break;
}
case ProxyType::WireGuard:
{
proxy.AddMember("type", "wireguard", allocator);
proxy.AddMember("tag", rapidjson::StringRef(x.Remark.c_str()), allocator);
rapidjson::Value addresses(rapidjson::kArrayType);
addresses.PushBack(rapidjson::StringRef(x.SelfIP.c_str()), allocator);
if (!x.SelfIPv6.empty())
addresses.PushBack(rapidjson::StringRef(x.SelfIPv6.c_str()), allocator);
proxy.AddMember("local_address", addresses, allocator);
proxy.AddMember("private_key", rapidjson::StringRef(x.PrivateKey.c_str()), allocator);
rapidjson::Value peer(rapidjson::kObjectType);
peer.AddMember("server", rapidjson::StringRef(x.Hostname.c_str()), allocator);
peer.AddMember("server_port", x.Port, allocator);
peer.AddMember("public_key", rapidjson::StringRef(x.PublicKey.c_str()), allocator);
if (!x.PreSharedKey.empty())
peer.AddMember("pre_shared_key", rapidjson::StringRef(x.PreSharedKey.c_str()), allocator);
if (!x.AllowedIPs.empty())
{
auto allowed = split(x.AllowedIPs, ",");
rapidjson::Value allowed_ips(rapidjson::kArrayType);
for (const auto &ip: allowed) {
allowed_ips.PushBack(rapidjson::Value(trim(ip).c_str(), allocator), allocator);
}
peer.AddMember("allowed_ips", allowed_ips, allocator);
}
if (!x.ClientId.empty())
{
auto client_id = split(x.ClientId, ",");
rapidjson::Value reserved(rapidjson::kArrayType);
for (const auto &id : client_id)
{
reserved.PushBack(to_int(trim(id)), allocator);
}
peer.AddMember("reserved", reserved, allocator);
}
rapidjson::Value peers(rapidjson::kArrayType);
peers.PushBack(peer, allocator);
proxy.AddMember("peers", peers, allocator);
proxy.AddMember("mtu", x.Mtu, allocator);
break;
}
case ProxyType::HTTP:
case ProxyType::HTTPS:
{
proxy.AddMember("type", "http", allocator);
proxy.AddMember("tag", rapidjson::StringRef(x.Remark.c_str()), allocator);
proxy.AddMember("server", rapidjson::StringRef(x.Hostname.c_str()), allocator);
proxy.AddMember("server_port", x.Port, allocator);
if (x.TLSSecure)
{
proxy.AddMember("username", rapidjson::StringRef(x.Username.c_str()), allocator);
proxy.AddMember("password", rapidjson::StringRef(x.Password.c_str()), allocator);
}
break;
}
case ProxyType::SOCKS5:
{
proxy.AddMember("type", "socks", allocator);
proxy.AddMember("tag", rapidjson::StringRef(x.Remark.c_str()), allocator);
proxy.AddMember("server", rapidjson::StringRef(x.Hostname.c_str()), allocator);
proxy.AddMember("port", x.Port, allocator);
proxy.AddMember("version", 5, allocator);
proxy.AddMember("username", rapidjson::StringRef(x.Username.c_str()), allocator);
proxy.AddMember("password", rapidjson::StringRef(x.Password.c_str()), allocator);
break;
}
default:
continue;
}
if (x.TLSSecure)
{
rapidjson::Value tls(rapidjson::kObjectType);
tls.AddMember("enable", true, allocator);
if (!x.ServerName.empty())
tls.AddMember("server_name", rapidjson::StringRef(x.ServerName.c_str()), allocator);
tls.AddMember("insecure", buildBooleanValue(scv), allocator);
proxy.AddMember("tls", tls, allocator);
}
if (!udp.is_undef() && !udp)
{
proxy.AddMember("network", "tcp", allocator);
}
if (!tfo.is_undef())
{
proxy.AddMember("tcp_fast_open", buildBooleanValue(tfo), allocator);
}
nodelist.push_back(x);
outbounds.PushBack(proxy, allocator);
}
for (const ProxyGroupConfig& x: extra_proxy_group)
{
string_array filtered_nodelist;
std::string type;
switch (x.Type)
{
case ProxyGroupType::Select:
{
type = "selector";
break;
}
case ProxyGroupType::URLTest:
case ProxyGroupType::Fallback:
case ProxyGroupType::LoadBalance:
{
type = "urltest";
break;
}
default:
continue;
}
for (const auto &y : x.Proxies)
groupGenerate(y, nodelist, filtered_nodelist, true, ext);
if (filtered_nodelist.empty())
filtered_nodelist.emplace_back("DIRECT");
rapidjson::Value group(rapidjson::kObjectType);
group.AddMember("type", rapidjson::Value(type.c_str(), allocator), allocator);
group.AddMember("tag", rapidjson::Value(x.Name.c_str(), allocator), allocator);
rapidjson::Value group_outbounds(rapidjson::kArrayType);
for (const std::string& y: filtered_nodelist)
{
group_outbounds.PushBack(rapidjson::Value(y.c_str(), allocator), allocator);
}
group.AddMember("outbounds", group_outbounds, allocator);
if (x.Type == ProxyGroupType::URLTest)
{
group.AddMember("url", rapidjson::Value(x.Url.c_str(), allocator), allocator);
group.AddMember("interval", rapidjson::Value(formatSingBoxInterval(x.Interval).c_str(), allocator), allocator);
if (x.Tolerance > 0)
group.AddMember("tolerance", x.Tolerance, allocator);
}
outbounds.PushBack(group, allocator);
}
if (json.HasMember("outbounds"))
json.RemoveMember("outbounds");
json.AddMember("outbounds", outbounds, allocator);
}
std::string proxyToSingBox(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<RulesetContent> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext)
{
rapidjson::Document json;
json.Parse(base_conf.data());
if(json.HasParseError())
{
writeLog(0, "sing-box base loader failed with error: " + std::string(rapidjson::GetParseError_En(json.GetParseError())), LOG_LEVEL_ERROR);
return "";
}
proxyToSingBox(nodes, json, ruleset_content_array, extra_proxy_group, ext);
rulesetToSingBox(json, ruleset_content_array, ext.overwrite_original_rules);
return SerializeObject(json);
}
+3 -5
View File
@@ -37,11 +37,11 @@ struct extra_settings
tribool skip_cert_verify = tribool();
tribool tls13 = tribool();
bool clash_classical_ruleset = false;
std::string sort_script = "";
std::string sort_script;
std::string clash_proxies_style = "flow";
bool authorized = false;
extra_settings() {};
extra_settings() = default;
extra_settings(const extra_settings&) = delete;
extra_settings(extra_settings&&) = delete;
@@ -57,9 +57,6 @@ struct extra_settings
#endif // NO_JS_RUNTIME
};
void rulesetToClash(YAML::Node &base_rule, std::vector<RulesetContent> &ruleset_content_array, bool overwrite_original_rules, bool new_field_name);
void rulesetToSurge(INIReader &base_rule, std::vector<RulesetContent> &ruleset_content_array, int surge_ver, bool overwrite_original_rules, std::string remote_path_prefix);
std::string proxyToClash(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<RulesetContent> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, bool clashR, extra_settings &ext);
void proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupConfigs &extra_proxy_group, bool clashR, extra_settings &ext);
std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<RulesetContent> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, int surge_ver, extra_settings &ext);
@@ -73,5 +70,6 @@ void proxyToQuanX(std::vector<Proxy> &nodes, INIReader &ini, std::vector<Ruleset
std::string proxyToQuan(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<RulesetContent> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext);
void proxyToQuan(std::vector<Proxy> &nodes, INIReader &ini, std::vector<RulesetContent> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext);
std::string proxyToSSD(std::vector<Proxy> &nodes, std::string &group, std::string &userinfo, extra_settings &ext);
std::string proxyToSingBox(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<RulesetContent> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext);
#endif // SUBEXPORT_H_INCLUDED