mirror of
https://github.com/asdlokj1qpi233/subconverter.git
synced 2026-11-03 02:02:24 +00:00
Enhancements
Add support for adding update interval to Clash rule-providers. Optimize performance. INIReader: Fix key value trimming error. INIReader: Fix not processing escape character when dumping.
This commit is contained in:
7 files changed
+204
-152
No files matched your search
+4
-4
@@ -79,10 +79,10 @@ rulesets:
|
||||
# - {rule: "GEOIP,CN", group: "DIRECT"}
|
||||
# - {ruleset: "rules/LocalAreaNetwork.list", group: "DIRECT"}
|
||||
# - {ruleset: "surge:rules/LocalAreaNetwork.list", group: "DIRECT"}
|
||||
# - {ruleset: "quanx:https://raw.githubusercontent.com/ConnersHua/Profiles/master/Quantumult/X/Filter/Advertising.list", group: "Advertising"}
|
||||
# - {ruleset: "clash-domain:https://ruleset.dev/clash_domestic_services_domains", group: "Domestic Services"}
|
||||
# - {ruleset: "clash-ipcidr:https://ruleset.dev/clash_domestic_services_ips", group: "Domestic Services"}
|
||||
# - {ruleset: "clash-classic:https://raw.githubusercontent.com/DivineEngine/Profiles/master/Clash/RuleSet/China.yaml", group: "DIRECT"}
|
||||
# - {ruleset: "quanx:https://raw.githubusercontent.com/ConnersHua/Profiles/master/Quantumult/X/Filter/Advertising.list", group: "Advertising", interval: 86400}
|
||||
# - {ruleset: "clash-domain:https://ruleset.dev/clash_domestic_services_domains", group: "Domestic Services", interval: 86400}
|
||||
# - {ruleset: "clash-ipcidr:https://ruleset.dev/clash_domestic_services_ips", group: "Domestic Services", interval: 86400}
|
||||
# - {ruleset: "clash-classic:https://raw.githubusercontent.com/DivineEngine/Profiles/master/Clash/RuleSet/China.yaml", group: "DIRECT", interval: 86400}
|
||||
- {import: snippets/rulesets.txt}
|
||||
|
||||
proxy_groups:
|
||||
|
||||
+6
-6
@@ -157,18 +157,18 @@ overwrite_original_rules=false
|
||||
update_ruleset_on_request=false
|
||||
|
||||
;Ruleset addresses, supports local files/URL
|
||||
;Format: Group name,[type:]URL
|
||||
;Format: Group name,[type:]URL[,interval]
|
||||
; Group name,[]Rule
|
||||
;where "type" supports the following value: surge, quanx, clash-domain, clash-ipcidr, clash-classic
|
||||
;type defaults to surge if omitted
|
||||
|
||||
;ruleset=DIRECT,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Unbreak.list
|
||||
;ruleset=DIRECT,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Unbreak.list,86400
|
||||
;ruleset=🎯 全球直连,rules/LocalAreaNetwork.list
|
||||
;ruleset=DIRECT,surge:rules/LocalAreaNetwork.list
|
||||
;ruleset=Advertising,quanx:https://raw.githubusercontent.com/ConnersHua/Profiles/master/Quantumult/X/Filter/Advertising.list
|
||||
;ruleset=Domestic Services,clash-domain:https://ruleset.dev/clash_domestic_services_domains
|
||||
;ruleset=Domestic Services,clash-ipcidr:https://ruleset.dev/clash_domestic_services_ips
|
||||
;ruleset=DIRECT,clash-classic:https://raw.githubusercontent.com/DivineEngine/Profiles/master/Clash/RuleSet/China.yaml
|
||||
;ruleset=Advertising,quanx:https://raw.githubusercontent.com/ConnersHua/Profiles/master/Quantumult/X/Filter/Advertising.list,86400
|
||||
;ruleset=Domestic Services,clash-domain:https://ruleset.dev/clash_domestic_services_domains,86400
|
||||
;ruleset=Domestic Services,clash-ipcidr:https://ruleset.dev/clash_domestic_services_ips,86400
|
||||
;ruleset=DIRECT,clash-classic:https://raw.githubusercontent.com/DivineEngine/Profiles/master/Clash/RuleSet/China.yaml,86400
|
||||
;ruleset=🎯 全球直连,[]GEOIP,CN
|
||||
;ruleset=🐟 漏网之鱼,[]FINAL
|
||||
|
||||
|
||||
+56
-57
@@ -41,7 +41,7 @@ private:
|
||||
string_array read_sections, section_order;
|
||||
|
||||
std::string cached_section;
|
||||
string_multimap cached_section_content;
|
||||
ini_data_struct::iterator cached_section_content;
|
||||
|
||||
std::string isolated_items_section;
|
||||
|
||||
@@ -248,14 +248,12 @@ public:
|
||||
|
||||
if(curSection.size() && (keep_empty_section || itemGroup.size())) //just finished reading a section
|
||||
{
|
||||
if(ini_content.count(curSection)) //a section with the same name has been inserted
|
||||
if(ini_content.find(curSection) != ini_content.end()) //a section with the same name has been inserted
|
||||
{
|
||||
if(allow_dup_section_titles || !ini_content.at(curSection).size())
|
||||
{
|
||||
eraseElements(existItemGroup);
|
||||
existItemGroup = ini_content.at(curSection); //get the old items
|
||||
for(auto &x : existItemGroup)
|
||||
itemGroup.emplace(x); //insert them all into new section
|
||||
itemGroup.merge(existItemGroup); //move old items to new sections
|
||||
}
|
||||
else if(ini_content.at(curSection).size())
|
||||
return __priv_save_error_and_return(INIREADER_EXCEPTION_DUPLICATE); //not allowed, stop
|
||||
@@ -263,9 +261,9 @@ public:
|
||||
}
|
||||
else if(itemGroup.size())
|
||||
read_sections.push_back(curSection); //add to read sections list
|
||||
ini_content.emplace(curSection, itemGroup); //insert previous section to content map
|
||||
if(std::count(section_order.cbegin(), section_order.cend(), curSection) == 0)
|
||||
section_order.emplace_back(std::move(curSection));
|
||||
if(std::find(section_order.cbegin(), section_order.cend(), curSection) == section_order.cend())
|
||||
section_order.emplace_back(curSection); //add to section order if not added before
|
||||
ini_content.emplace(std::move(curSection), std::move(itemGroup)); //insert previous section to content map
|
||||
}
|
||||
|
||||
eraseElements(itemGroup); //reset section storage
|
||||
@@ -281,23 +279,25 @@ public:
|
||||
continue;
|
||||
if(!curSection.size()) //not in any section
|
||||
return __priv_save_error_and_return(INIREADER_EXCEPTION_OUTOFBOUND);
|
||||
itemName = trim(strLine.substr(0, strLine.find("=")));
|
||||
itemVal = trim(strLine.substr(strLine.find("=") + 1));
|
||||
itemGroup.emplace(itemName, itemVal); //insert to current section
|
||||
string_size pose = strLine.find("="), posc = strLine.find_first_not_of(' ', pose + 1);
|
||||
itemName = trim(strLine.substr(0, pose));
|
||||
if(posc != strLine.npos) //not a key with empty value
|
||||
{
|
||||
itemVal = strLine.substr(posc);
|
||||
itemGroup.emplace(std::move(itemName), std::move(itemVal)); //insert to current section
|
||||
}
|
||||
}
|
||||
if(include_sections.size() && include_sections == read_sections) //all included sections has been read
|
||||
break; //exit now
|
||||
}
|
||||
if(curSection.size() && (keep_empty_section || itemGroup.size())) //final section
|
||||
{
|
||||
if(ini_content.count(curSection)) //a section with the same name has been inserted
|
||||
if(ini_content.find(curSection) != ini_content.end()) //a section with the same name has been inserted
|
||||
{
|
||||
if(allow_dup_section_titles)
|
||||
{
|
||||
eraseElements(existItemGroup);
|
||||
existItemGroup = ini_content.at(curSection); //get the old items
|
||||
for(auto &x : existItemGroup)
|
||||
itemGroup.emplace(x); //insert them all into new section
|
||||
itemGroup.merge(existItemGroup); //move old items to new sections
|
||||
}
|
||||
else if(ini_content.at(curSection).size())
|
||||
return __priv_save_error_and_return(INIREADER_EXCEPTION_DUPLICATE); //not allowed, stop
|
||||
@@ -305,9 +305,9 @@ public:
|
||||
}
|
||||
else if(itemGroup.size())
|
||||
read_sections.emplace_back(curSection); //add to read sections list
|
||||
ini_content.emplace(curSection, itemGroup); //insert this section to content map
|
||||
if(std::count(section_order.cbegin(), section_order.cend(), curSection) == 0)
|
||||
section_order.emplace_back(curSection);
|
||||
if(std::find(section_order.cbegin(), section_order.cend(), curSection) == section_order.cend())
|
||||
section_order.emplace_back(curSection); //add to section order if not added before
|
||||
ini_content.emplace(std::move(curSection), std::move(itemGroup)); //insert this section to content map
|
||||
}
|
||||
parsed = true;
|
||||
return __priv_save_error_and_return(INIREADER_EXCEPTION_NONE); //all done
|
||||
@@ -355,7 +355,7 @@ public:
|
||||
if(!SectionExist(section))
|
||||
return __priv_save_error_and_return(INIREADER_EXCEPTION_NOTEXIST);
|
||||
current_section = cached_section = section;
|
||||
cached_section_content = ini_content.at(section);
|
||||
cached_section_content = ini_content.find(section);
|
||||
return __priv_save_error_and_return(INIREADER_EXCEPTION_NONE);
|
||||
}
|
||||
|
||||
@@ -378,10 +378,10 @@ public:
|
||||
if(section != cached_section)
|
||||
{
|
||||
cached_section = section;
|
||||
cached_section_content= ini_content.at(section);
|
||||
cached_section_content= ini_content.find(section);
|
||||
}
|
||||
|
||||
return cached_section_content.find(itemName) != cached_section_content.end();
|
||||
auto &cache = cached_section_content->second;
|
||||
return cache.find(itemName) != cache.end();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -403,10 +403,10 @@ public:
|
||||
if(section != cached_section)
|
||||
{
|
||||
cached_section = section;
|
||||
cached_section_content= ini_content.at(section);
|
||||
cached_section_content = ini_content.find(section);
|
||||
}
|
||||
|
||||
for(auto &x : cached_section_content)
|
||||
for(auto &x : cached_section_content->second)
|
||||
{
|
||||
if(x.first.find(itemName) == 0)
|
||||
return true;
|
||||
@@ -441,24 +441,34 @@ public:
|
||||
{
|
||||
eraseElements(ini_content);
|
||||
eraseElements(section_order);
|
||||
cached_section.clear();
|
||||
cached_section_content = ini_content.end();
|
||||
parsed = false;
|
||||
}
|
||||
|
||||
ini_data_struct::iterator GetItemsRef(const std::string §ion)
|
||||
{
|
||||
if(!parsed || !SectionExist(section))
|
||||
return ini_content.end();
|
||||
|
||||
if(cached_section != section)
|
||||
{
|
||||
cached_section = section;
|
||||
cached_section_content = ini_content.find(section);
|
||||
}
|
||||
return cached_section_content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieve all items in the given section.
|
||||
*/
|
||||
int GetItems(const std::string §ion, string_multimap &data)
|
||||
{
|
||||
if(!parsed || !SectionExist(section))
|
||||
auto section_ref = GetItemsRef(section);
|
||||
if(section_ref == ini_content.end())
|
||||
return __priv_save_error_and_return(INIREADER_EXCEPTION_NOTEXIST);
|
||||
|
||||
if(cached_section != section)
|
||||
{
|
||||
cached_section = section;
|
||||
cached_section_content = ini_content.at(section);
|
||||
}
|
||||
|
||||
data = cached_section_content;
|
||||
data = section_ref->second;
|
||||
return __priv_save_error_and_return(INIREADER_EXCEPTION_NONE);
|
||||
}
|
||||
|
||||
@@ -478,12 +488,11 @@ public:
|
||||
if(!parsed)
|
||||
return __priv_save_error_and_return(INIREADER_EXCEPTION_NOTPARSED);
|
||||
|
||||
string_multimap mapTemp;
|
||||
|
||||
if(GetItems(section, mapTemp) != 0)
|
||||
auto section_ref = GetItemsRef(section);
|
||||
if(section_ref == ini_content.end())
|
||||
return __priv_save_error_and_return(INIREADER_EXCEPTION_NOTEXIST);
|
||||
|
||||
for(auto &x : mapTemp)
|
||||
for(auto &x : section_ref->second)
|
||||
{
|
||||
if(x.first.find(itemName) == 0)
|
||||
results.emplace_back(x.second);
|
||||
@@ -507,20 +516,16 @@ public:
|
||||
{
|
||||
if(!parsed || !SectionExist(section))
|
||||
return std::string();
|
||||
/*
|
||||
string_multimap mapTemp;
|
||||
|
||||
if(GetItems(section, mapTemp) != 0)
|
||||
return std::string();
|
||||
*/
|
||||
if(cached_section != section)
|
||||
{
|
||||
cached_section = section;
|
||||
cached_section_content = ini_content.at(section);
|
||||
cached_section_content = ini_content.find(section);
|
||||
}
|
||||
|
||||
auto iter = std::find_if(cached_section_content.begin(), cached_section_content.end(), [&](auto x) { return x.first == itemName; });
|
||||
if(iter != cached_section_content.end())
|
||||
auto &cache = cached_section_content->second;
|
||||
auto iter = std::find_if(cache.begin(), cache.end(), [&](auto x) { return x.first == itemName; });
|
||||
if(iter != cache.end())
|
||||
return iter->second;
|
||||
|
||||
return std::string();
|
||||
@@ -804,13 +809,9 @@ public:
|
||||
{
|
||||
if(!SectionExist(oldName) || SectionExist(newName))
|
||||
return __priv_save_error_and_return(INIREADER_EXCEPTION_DUPLICATE);
|
||||
/*
|
||||
auto nodeHandler = ini_content.extract(oldName);
|
||||
nodeHandler.key() = newName;
|
||||
ini_content.insert(std::move(nodeHandler));
|
||||
*/
|
||||
ini_content[newName] = std::move(ini_content[oldName]);
|
||||
ini_content.erase(oldName);
|
||||
std::replace(section_order.begin(), section_order.end(), oldName, newName);
|
||||
return __priv_save_error_and_return(INIREADER_EXCEPTION_NONE);
|
||||
}
|
||||
@@ -827,7 +828,7 @@ public:
|
||||
retVal = ini_content.at(section).erase(itemName);
|
||||
if(retVal && cached_section == section)
|
||||
{
|
||||
cached_section_content = ini_content.at(section);
|
||||
cached_section_content = ini_content.find(section);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
@@ -850,10 +851,6 @@ public:
|
||||
if(iter != mapTemp.end())
|
||||
{
|
||||
mapTemp.erase(iter);
|
||||
if(cached_section == section)
|
||||
{
|
||||
cached_section_content = mapTemp;
|
||||
}
|
||||
return __priv_save_error_and_return(INIREADER_EXCEPTION_NONE);
|
||||
}
|
||||
else
|
||||
@@ -880,7 +877,7 @@ public:
|
||||
eraseElements(ini_content.at(section));
|
||||
if(cached_section == section)
|
||||
{
|
||||
eraseElements(cached_section_content);
|
||||
cached_section_content = ini_content.end();
|
||||
cached_section.erase();
|
||||
}
|
||||
//section_order.erase(std::find(section_order.begin(), section_order.end(), section));
|
||||
@@ -900,7 +897,7 @@ public:
|
||||
*/
|
||||
std::string ToString()
|
||||
{
|
||||
std::string content;
|
||||
std::string content, itemVal;
|
||||
|
||||
if(!parsed)
|
||||
return std::string();
|
||||
@@ -921,9 +918,11 @@ public:
|
||||
{
|
||||
if(iter->first != "{NONAME}")
|
||||
content += iter->first + "=";
|
||||
content += iter->second + "\n";
|
||||
itemVal = iter->second;
|
||||
ProcessEscapeCharReverse(itemVal);
|
||||
content += itemVal + "\n";
|
||||
if(std::next(iter) == section.end())
|
||||
strsize = iter->second.size();
|
||||
strsize = itemVal.size();
|
||||
}
|
||||
}
|
||||
if(strsize)
|
||||
|
||||
+22
-41
@@ -91,6 +91,8 @@ std::string parseProxy(const std::string &source)
|
||||
const string_array clash_rule_type = {basic_types, "IP-CIDR6", "SRC-PORT", "DST-PORT"};
|
||||
const string_array surge_rule_type = {basic_types, "IP-CIDR6", "USER-AGENT", "URL-REGEX", "AND", "OR", "NOT", "PROCESS-NAME", "IN-PORT", "DEST-PORT", "SRC-IP"};
|
||||
const string_array quanx_rule_type = {basic_types, "USER-AGENT", "HOST", "HOST-SUFFIX", "HOST-KEYWORD"};
|
||||
const std::map<std::string, ruleset_type> ruleset_types = {{"clash-domain:", RULESET_CLASH_DOMAIN}, {"clash-ipcidr:", RULESET_CLASH_IPCIDR}, {"clash-classic:", RULESET_CLASH_CLASSICAL}, \
|
||||
{"quanx:", RULESET_QUANX}, {"surge:", RULESET_SURGE}};
|
||||
|
||||
std::string convertRuleset(const std::string &content, int type)
|
||||
{
|
||||
@@ -487,7 +489,7 @@ void readGroup(YAML::Node node, string_array &dest, bool scope_limit = true)
|
||||
|
||||
void readRuleset(YAML::Node node, string_array &dest, bool scope_limit = true)
|
||||
{
|
||||
std::string strLine, name, url, group;
|
||||
std::string strLine, name, url, group, interval;
|
||||
YAML::Node object;
|
||||
|
||||
for(unsigned int i = 0; i < node.size(); i++)
|
||||
@@ -502,8 +504,13 @@ void readRuleset(YAML::Node node, string_array &dest, bool scope_limit = true)
|
||||
object["ruleset"] >>= url;
|
||||
object["group"] >>= group;
|
||||
object["rule"] >>= name;
|
||||
object["interval"] >>= interval;
|
||||
if(url.size())
|
||||
{
|
||||
strLine = group + "," + url;
|
||||
if(interval.size())
|
||||
strLine += "," + interval;
|
||||
}
|
||||
else if(name.size())
|
||||
strLine = group + ",[]" + name;
|
||||
else
|
||||
@@ -516,69 +523,43 @@ void readRuleset(YAML::Node node, string_array &dest, bool scope_limit = true)
|
||||
void refreshRulesets(string_array &ruleset_list, std::vector<ruleset_content> &rca)
|
||||
{
|
||||
eraseElements(rca);
|
||||
std::string rule_group, rule_url, rule_url_typed;
|
||||
std::string rule_group, rule_url, rule_url_typed, interval;
|
||||
ruleset_content rc;
|
||||
|
||||
std::string proxy = parseProxy(proxy_ruleset);
|
||||
|
||||
for(std::string &x : ruleset_list)
|
||||
{
|
||||
/*
|
||||
vArray = split(x, ",");
|
||||
if(vArray.size() != 2)
|
||||
continue;
|
||||
rule_group = trim(vArray[0]);
|
||||
rule_url = trim(vArray[1]);
|
||||
*/
|
||||
string_size pos = x.find(",");
|
||||
if(pos == x.npos)
|
||||
if(pos == x.npos || pos == x.size() - 1)
|
||||
continue;
|
||||
rule_group = trim(x.substr(0, pos));
|
||||
rule_url = trim(x.substr(pos + 1));
|
||||
if(rule_url.find("[]") == 0)
|
||||
if(x.find("[]", pos + 1) == pos + 1)
|
||||
{
|
||||
rule_url = trim(x.substr(pos + 1));
|
||||
writeLog(0, "Adding rule '" + rule_url.substr(2) + "," + rule_group + "'.", LOG_LEVEL_INFO);
|
||||
//std::cerr<<"Adding rule '"<<rule_url.substr(2)<<","<<rule_group<<"'."<<std::endl;
|
||||
rc = {rule_group, "", "", RULESET_SURGE, std::async(std::launch::async, [rule_url](){return rule_url;})};
|
||||
rca.emplace_back(std::move(rc));
|
||||
continue;
|
||||
rc = {rule_group, "", "", RULESET_SURGE, std::async(std::launch::async, [rule_url](){return rule_url;}), 0};
|
||||
}
|
||||
else
|
||||
{
|
||||
string_size pos2 = x.find(",", pos + 1);
|
||||
rule_url = trim(x.substr(pos + 1, pos2 - pos - 1));
|
||||
if(pos2 != x.npos)
|
||||
interval = x.substr(pos2 + 1);
|
||||
else
|
||||
interval.clear();
|
||||
ruleset_type type = RULESET_SURGE;
|
||||
const std::map<std::string, ruleset_type> types = {{"clash-domain:", RULESET_CLASH_DOMAIN}, {"clash-ipcidr:", RULESET_CLASH_IPCIDR}, {"clash-classic:", RULESET_CLASH_CLASSICAL}, \
|
||||
{"quanx:", RULESET_QUANX}, {"surge:", RULESET_SURGE}};
|
||||
rule_url_typed = rule_url;
|
||||
auto iter = std::find_if(types.begin(), types.end(), [rule_url](auto y){ return startsWith(rule_url, y.first); });
|
||||
if(iter != types.end())
|
||||
auto iter = std::find_if(ruleset_types.begin(), ruleset_types.end(), [rule_url](auto y){ return startsWith(rule_url, y.first); });
|
||||
if(iter != ruleset_types.end())
|
||||
{
|
||||
rule_url.erase(0, iter->first.size());
|
||||
type = iter->second;
|
||||
}
|
||||
//std::cerr<<"Updating ruleset url '"<<rule_url<<"' with group '"<<rule_group<<"'."<<std::endl;
|
||||
writeLog(0, "Updating ruleset url '" + rule_url + "' with group '" + rule_group + "'.", LOG_LEVEL_INFO);
|
||||
/*
|
||||
if(fileExist(rule_url))
|
||||
{
|
||||
rc = {rule_group, rule_url, fileGet(rule_url)};
|
||||
}
|
||||
else if(startsWith(rule_url, "https://") || startsWith(rule_url, "http://") || startsWith(rule_url, "data:"))
|
||||
{
|
||||
rc = {rule_group, rule_url, webGet(rule_url, proxy, dummy, cache_ruleset)};
|
||||
}
|
||||
else
|
||||
continue;
|
||||
*/
|
||||
rc = {rule_group, rule_url, rule_url_typed, type, fetchFileAsync(rule_url, proxy, cache_ruleset, async_fetch_ruleset)};
|
||||
rc = {rule_group, rule_url, rule_url_typed, type, fetchFileAsync(rule_url, proxy, cache_ruleset, async_fetch_ruleset), to_int(interval, 0)};
|
||||
}
|
||||
rca.emplace_back(std::move(rc));
|
||||
/*
|
||||
if(rc.rule_content.get().size())
|
||||
rca.emplace_back(rc);
|
||||
else
|
||||
//std::cerr<<"Warning: No data was fetched from this link. Skipping..."<<std::endl;
|
||||
writeLog(0, "Warning: No data was fetched from ruleset '" + rule_url + "'. Skipping...", LOG_LEVEL_WARNING);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+39
-7
@@ -451,14 +451,20 @@ std::string getSystemProxy()
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
std::string trim_of(const std::string& str, char target)
|
||||
std::string trim_of(const std::string& str, char target, bool before, bool after)
|
||||
{
|
||||
std::string::size_type pos = str.find_first_not_of(target);
|
||||
if (!before && !after)
|
||||
return str;
|
||||
std::string::size_type pos = 0;
|
||||
if (before)
|
||||
pos = str.find_first_not_of(target);
|
||||
if (pos == std::string::npos)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
std::string::size_type pos2 = str.find_last_not_of(target);
|
||||
std::string::size_type pos2 = str.size() - 1;
|
||||
if (after)
|
||||
pos2 = str.find_last_not_of(target);
|
||||
if (pos2 != std::string::npos)
|
||||
{
|
||||
return str.substr(pos, pos2 - pos + 1);
|
||||
@@ -466,14 +472,14 @@ std::string trim_of(const std::string& str, char target)
|
||||
return str.substr(pos);
|
||||
}
|
||||
|
||||
std::string trim(const std::string& str)
|
||||
std::string trim(const std::string& str, bool before, bool after)
|
||||
{
|
||||
return trim_of(str, ' ');
|
||||
return trim_of(str, ' ', before, after);
|
||||
}
|
||||
|
||||
std::string trim_quote(const std::string &str)
|
||||
std::string trim_quote(const std::string &str, bool before, bool after)
|
||||
{
|
||||
return trim_of(str, '\"');
|
||||
return trim_of(str, '\"', before, after);
|
||||
}
|
||||
|
||||
std::string getUrlArg(const std::string &url, const std::string &request)
|
||||
@@ -1064,6 +1070,8 @@ void shortDisassemble(int source, unsigned short &num_a, unsigned short &num_b)
|
||||
|
||||
int to_int(const std::string &str, int def_value)
|
||||
{
|
||||
if(str.empty())
|
||||
return def_value;
|
||||
int retval = 0;
|
||||
char c;
|
||||
std::stringstream ss(str);
|
||||
@@ -1201,3 +1209,27 @@ void ProcessEscapeChar(std::string &str)
|
||||
pos = str.find('\\', pos + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessEscapeCharReverse(std::string &str)
|
||||
{
|
||||
string_size pos = 0;
|
||||
while(pos < str.size())
|
||||
{
|
||||
switch(str[pos])
|
||||
{
|
||||
case '\n':
|
||||
str.replace(pos, 1, "\\n");
|
||||
break;
|
||||
case '\r':
|
||||
str.replace(pos, 1, "\\r");
|
||||
break;
|
||||
case '\t':
|
||||
str.replace(pos, 1, "\\t");
|
||||
break;
|
||||
default:
|
||||
/// ignore others for backward compatibility
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -52,9 +52,9 @@ std::string urlsafe_base64_decode(const std::string &encoded_string);
|
||||
std::string urlsafe_base64_encode(const std::string &string_to_encode);
|
||||
std::string UTF8ToACP(const std::string &str_src);
|
||||
std::string ACPToUTF8(const std::string &str_src);
|
||||
std::string trim_of(const std::string& str, char target);
|
||||
std::string trim(const std::string& str);
|
||||
std::string trim_quote(const std::string &str);
|
||||
std::string trim_of(const std::string& str, char target, bool before = true, bool after = true);
|
||||
std::string trim(const std::string& str, bool before = true, bool after = true);
|
||||
std::string trim_quote(const std::string &str, bool before = true, bool after = true);
|
||||
std::string getSystemProxy();
|
||||
std::string rand_str(const int len);
|
||||
bool is_str_utf8(const std::string &data);
|
||||
@@ -80,6 +80,7 @@ std::string GetEnv(const std::string &name);
|
||||
std::string toLower(const std::string &str);
|
||||
std::string toUpper(const std::string &str);
|
||||
void ProcessEscapeChar(std::string &str);
|
||||
void ProcessEscapeCharReverse(std::string &str);
|
||||
|
||||
std::string fileGet(const std::string &path, bool scope_limit = false);
|
||||
int fileWrite(const std::string &path, const std::string &content, bool overwrite);
|
||||
|
||||
+73
-34
@@ -192,7 +192,6 @@ const std::string clash_script_template = R"(def main(ctx, md):
|
||||
host = md["host"]
|
||||
{% for rule in rules %}
|
||||
{% if rule.set == "true" %}{% include "group_template" %}{% endif %}
|
||||
{% if not rule.keyword == "" %}{% include "keyword_template" %}{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if exists("geoips") %} geoips = { {{ geoips }} }
|
||||
@@ -207,11 +206,12 @@ const std::string clash_script_template = R"(def main(ctx, md):
|
||||
return geoips[key]{% endif %}
|
||||
return "{{ match_group }}")";
|
||||
|
||||
const std::string clash_script_group_template = R"({% if rule.has_domain == "false" and rule.has_ipcidr == "false" %} if ctx.rule_providers["{{ rule.name }}_classical"].match(md):
|
||||
const std::string clash_script_group_template = R"({% if rule.has_domain == "false" and rule.has_ipcidr == "false" %} if ctx.rule_providers["{{ rule.name }}"].match(md):
|
||||
ctx.log('[Script] matched {{ rule.group }} rule')
|
||||
return "{{ rule.group }}"{% else %}{% if rule.has_domain == "true" %} if ctx.rule_providers["{{ rule.name }}_domain"].match(md):
|
||||
ctx.log('[Script] matched {{ rule.group }} DOMAIN rule')
|
||||
return "{{ rule.group }}"{% endif %}
|
||||
{% if not rule.keyword == "" %}{% include "keyword_template" %}{% endif %}
|
||||
{% if rule.has_ipcidr == "true" %} if ctx.rule_providers["{{ rule.name }}_ipcidr"].match(md):
|
||||
ctx.log('[Script] matched {{ rule.group }} IP rule')
|
||||
return "{{ rule.group }}"{% endif %}{% endif %})";
|
||||
@@ -222,15 +222,31 @@ const std::string clash_script_keyword_template = R"( keywords = [{{ rule.keywo
|
||||
ctx.log('[Script] matched {{ rule.group }} DOMAIN-KEYWORD rule')
|
||||
return "{{ rule.group }}")";
|
||||
|
||||
std::string findFileName(const std::string &path)
|
||||
{
|
||||
string_size pos = path.rfind('/');
|
||||
if(pos == path.npos)
|
||||
{
|
||||
pos = path.rfind('\\');
|
||||
if(pos == path.npos)
|
||||
pos = 0;
|
||||
}
|
||||
string_size pos2 = path.rfind('.');
|
||||
if(pos2 < pos)
|
||||
pos2 = path.size() - 1;
|
||||
return path.substr(pos + 1, pos2 - pos - 1);
|
||||
}
|
||||
|
||||
int renderClashScript(YAML::Node &base_rule, std::vector<ruleset_content> &ruleset_content_array, std::string remote_path_prefix, bool script, bool overwrite_original_rules, bool clash_classical_ruleset)
|
||||
{
|
||||
nlohmann::json data;
|
||||
std::string match_group, geoips, retrieved_rules;
|
||||
std::string strLine, rule_group, rule_path, rule_path_typed, rule_name;
|
||||
std::string strLine, rule_group, rule_path, rule_path_typed, rule_name, old_rule_name;
|
||||
std::stringstream strStrm;
|
||||
string_array vArray, groups;
|
||||
string_map keywords, urls, names;
|
||||
std::map<std::string, bool> has_domain, has_ipcidr;
|
||||
std::map<std::string, int> ruleset_interval;
|
||||
string_array rules;
|
||||
int index = 0;
|
||||
|
||||
@@ -270,24 +286,29 @@ int renderClashScript(YAML::Node &base_rule, std::vector<ruleset_content> &rules
|
||||
{
|
||||
if(x.rule_type == RULESET_CLASH_IPCIDR || x.rule_type == RULESET_CLASH_DOMAIN || x.rule_type == RULESET_CLASH_CLASSICAL)
|
||||
{
|
||||
rule_name = std::to_string(hash_(rule_group + rule_path));
|
||||
//rule_name = std::to_string(hash_(rule_group + rule_path));
|
||||
rule_name = old_rule_name = findFileName(rule_path);
|
||||
int idx = 2;
|
||||
while(std::find(groups.begin(), groups.end(), rule_name) != groups.end())
|
||||
rule_name = old_rule_name + "_" + std::to_string(idx++);
|
||||
names[rule_name] = rule_group;
|
||||
urls[rule_name] = "*" + rule_path;
|
||||
ruleset_interval[rule_name] = x.update_interval;
|
||||
switch(x.rule_type)
|
||||
{
|
||||
case RULESET_CLASH_IPCIDR:
|
||||
has_ipcidr[rule_name] = true;
|
||||
if(!script)
|
||||
rules.emplace_back("RULE-SET," + rule_group + "_" + rule_name + "_ipcidr," + rule_group);
|
||||
rules.emplace_back("RULE-SET," + rule_name + "_ipcidr," + rule_group);
|
||||
break;
|
||||
case RULESET_CLASH_DOMAIN:
|
||||
has_domain[rule_name] = true;
|
||||
if(!script)
|
||||
rules.emplace_back("RULE-SET," + rule_group + "_" + rule_name + "_domain," + rule_group);
|
||||
rules.emplace_back("RULE-SET," + rule_name + "_domain," + rule_group);
|
||||
break;
|
||||
case RULESET_CLASH_CLASSICAL:
|
||||
if(!script)
|
||||
rules.emplace_back("RULE-SET," + rule_group + "_" + rule_name + "_classical," + rule_group);
|
||||
rules.emplace_back("RULE-SET," + rule_name + "," + rule_group);
|
||||
break;
|
||||
}
|
||||
groups.emplace_back(std::move(rule_name));
|
||||
@@ -297,13 +318,18 @@ int renderClashScript(YAML::Node &base_rule, std::vector<ruleset_content> &rules
|
||||
{
|
||||
if(fileExist(rule_path, true) || isLink(rule_path))
|
||||
{
|
||||
rule_name = std::to_string(hash_(rule_group + rule_path));
|
||||
//rule_name = std::to_string(hash_(rule_group + rule_path));
|
||||
rule_name = old_rule_name = findFileName(rule_path);
|
||||
int idx = 2;
|
||||
while(std::find(groups.begin(), groups.end(), rule_name) != groups.end())
|
||||
rule_name = old_rule_name + "_" + std::to_string(idx++);
|
||||
names[rule_name] = rule_group;
|
||||
urls[rule_name] = rule_path_typed;
|
||||
ruleset_interval[rule_name] = x.update_interval;
|
||||
if(clash_classical_ruleset)
|
||||
{
|
||||
if(!script)
|
||||
rules.emplace_back("RULE-SET," + rule_group + "_" + rule_name + "_classical," + rule_group);
|
||||
rules.emplace_back("RULE-SET," + rule_name + "," + rule_group);
|
||||
groups.emplace_back(std::move(rule_name));
|
||||
continue;
|
||||
}
|
||||
@@ -359,66 +385,79 @@ int renderClashScript(YAML::Node &base_rule, std::vector<ruleset_content> &rules
|
||||
has_ipcidr[rule_name] = true;
|
||||
}
|
||||
if(has_domain[rule_name] && !script)
|
||||
rules.emplace_back("RULE-SET," + rule_group + "_" + rule_name + "_domain," + rule_group);
|
||||
rules.emplace_back("RULE-SET," + rule_name + "_domain," + rule_group);
|
||||
if(has_ipcidr[rule_name] && !script)
|
||||
rules.emplace_back("RULE-SET," + rule_group + "_" + rule_name + "_ipcidr," + rule_group);
|
||||
rules.emplace_back("RULE-SET," + rule_name + "_ipcidr," + rule_group);
|
||||
if(std::find(groups.begin(), groups.end(), rule_name) == groups.end())
|
||||
groups.emplace_back(std::move(rule_name));
|
||||
}
|
||||
}
|
||||
for(std::string &x : groups)
|
||||
{
|
||||
std::string json_path = "rules." + std::to_string(index) + ".";
|
||||
std::string url = urls[x], keyword = keywords[x], name = names[x];
|
||||
bool group_has_domain = has_domain[x], group_has_ipcidr = has_ipcidr[x];
|
||||
int interval = ruleset_interval[x];
|
||||
if(clash_classical_ruleset)
|
||||
{
|
||||
base_rule["rule-providers"][name + "_" + x + "_classical"]["type"] = "http";
|
||||
base_rule["rule-providers"][name + "_" + x + "_classical"]["behavior"] = "classical";
|
||||
std::string yaml_key = x;
|
||||
base_rule["rule-providers"][yaml_key]["type"] = "http";
|
||||
base_rule["rule-providers"][yaml_key]["behavior"] = "classical";
|
||||
if(url[0] == '*')
|
||||
base_rule["rule-providers"][name + "_" + x + "_classical"]["url"] = url.substr(1);
|
||||
base_rule["rule-providers"][yaml_key]["url"] = url.substr(1);
|
||||
else
|
||||
base_rule["rule-providers"][name + "_" + x + "_classical"]["url"] = remote_path_prefix + "/getruleset?type=6&url=" + urlsafe_base64_encode(url);
|
||||
base_rule["rule-providers"][name + "_" + x + "_classical"]["path"] = "./providers/rule-provider_" + x + "_classical.yaml";
|
||||
base_rule["rule-providers"][yaml_key]["url"] = remote_path_prefix + "/getruleset?type=6&url=" + urlsafe_base64_encode(url);
|
||||
base_rule["rule-providers"][yaml_key]["path"] = "./providers/rule-provider_" + x + "_classical.yaml";
|
||||
if(interval)
|
||||
base_rule["rule-providers"][yaml_key]["interval"] = interval;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(group_has_domain)
|
||||
{
|
||||
base_rule["rule-providers"][name + "_" + x + "_domain"]["type"] = "http";
|
||||
base_rule["rule-providers"][name + "_" + x + "_domain"]["behavior"] = "domain";
|
||||
std::string yaml_key = x + "_domain";
|
||||
base_rule["rule-providers"][yaml_key]["type"] = "http";
|
||||
base_rule["rule-providers"][yaml_key]["behavior"] = "domain";
|
||||
if(url[0] == '*')
|
||||
base_rule["rule-providers"][name + "_" + x + "_domain"]["url"] = url.substr(1);
|
||||
base_rule["rule-providers"][yaml_key]["url"] = url.substr(1);
|
||||
else
|
||||
base_rule["rule-providers"][name + "_" + x + "_domain"]["url"] = remote_path_prefix + "/getruleset?type=3&url=" + urlsafe_base64_encode(url);
|
||||
base_rule["rule-providers"][name + "_" + x + "_domain"]["path"] = "./providers/rule-provider_" + x + "_domain.yaml";
|
||||
base_rule["rule-providers"][yaml_key]["url"] = remote_path_prefix + "/getruleset?type=3&url=" + urlsafe_base64_encode(url);
|
||||
base_rule["rule-providers"][yaml_key]["path"] = "./providers/rule-provider_" + x + "_domain.yaml";
|
||||
if(interval)
|
||||
base_rule["rule-providers"][yaml_key]["interval"] = interval;
|
||||
}
|
||||
if(group_has_ipcidr)
|
||||
{
|
||||
base_rule["rule-providers"][name + "_" + x + "_ipcidr"]["type"] = "http";
|
||||
base_rule["rule-providers"][name + "_" + x + "_ipcidr"]["behavior"] = "ipcidr";
|
||||
std::string yaml_key = x + "_ipcidr";
|
||||
base_rule["rule-providers"][yaml_key]["type"] = "http";
|
||||
base_rule["rule-providers"][yaml_key]["behavior"] = "ipcidr";
|
||||
if(url[0] == '*')
|
||||
base_rule["rule-providers"][name + "_" + x + "_ipcidr"]["url"] = url.substr(1);
|
||||
base_rule["rule-providers"][yaml_key]["url"] = url.substr(1);
|
||||
else
|
||||
base_rule["rule-providers"][name + "_" + x + "_ipcidr"]["url"] = remote_path_prefix + "/getruleset?type=4&url=" + urlsafe_base64_encode(url);
|
||||
base_rule["rule-providers"][name + "_" + x + "_ipcidr"]["path"] = "./providers/rule-provider_" + x + "_ipcidr.yaml";
|
||||
base_rule["rule-providers"][yaml_key]["url"] = remote_path_prefix + "/getruleset?type=4&url=" + urlsafe_base64_encode(url);
|
||||
base_rule["rule-providers"][yaml_key]["path"] = "./providers/rule-provider_" + x + "_ipcidr.yaml";
|
||||
if(interval)
|
||||
base_rule["rule-providers"][yaml_key]["interval"] = interval;
|
||||
}
|
||||
if(!group_has_domain && !group_has_ipcidr)
|
||||
{
|
||||
base_rule["rule-providers"][name + "_" + x + "_classical"]["type"] = "http";
|
||||
base_rule["rule-providers"][name + "_" + x + "_classical"]["behavior"] = "classical";
|
||||
std::string yaml_key = x;
|
||||
base_rule["rule-providers"][yaml_key]["type"] = "http";
|
||||
base_rule["rule-providers"][yaml_key]["behavior"] = "classical";
|
||||
if(url[0] == '*')
|
||||
base_rule["rule-providers"][name + "_" + x + "_classical"]["url"] = url.substr(1);
|
||||
base_rule["rule-providers"][yaml_key]["url"] = url.substr(1);
|
||||
else
|
||||
base_rule["rule-providers"][name + "_" + x + "_classical"]["url"] = remote_path_prefix + "/getruleset?type=6&url=" + urlsafe_base64_encode(url);
|
||||
base_rule["rule-providers"][name + "_" + x + "_classical"]["path"] = "./providers/rule-provider_" + x + "_classical.yaml";
|
||||
base_rule["rule-providers"][yaml_key]["url"] = remote_path_prefix + "/getruleset?type=6&url=" + urlsafe_base64_encode(url);
|
||||
base_rule["rule-providers"][yaml_key]["path"] = "./providers/rule-provider_" + x + "_classical.yaml";
|
||||
if(interval)
|
||||
base_rule["rule-providers"][yaml_key]["interval"] = interval;
|
||||
}
|
||||
}
|
||||
if(script)
|
||||
{
|
||||
std::string json_path = "rules." + std::to_string(index) + ".";
|
||||
parse_json_pointer(data, json_path + "has_domain", group_has_domain ? "true" : "false");
|
||||
parse_json_pointer(data, json_path + "has_ipcidr", group_has_ipcidr ? "true" : "false");
|
||||
parse_json_pointer(data, json_path + "name", name + "_" + x);
|
||||
parse_json_pointer(data, json_path + "name", x);
|
||||
parse_json_pointer(data, json_path + "group", name);
|
||||
parse_json_pointer(data, json_path + "set", "true");
|
||||
parse_json_pointer(data, json_path + "keyword", keyword);
|
||||
@@ -433,8 +472,8 @@ int renderClashScript(YAML::Node &base_rule, std::vector<ruleset_content> &rules
|
||||
parse_json_pointer(data, "match_group", match_group);
|
||||
|
||||
inja::Environment env;
|
||||
env.include_template("group_template", env.parse(clash_script_group_template));
|
||||
env.include_template("keyword_template", env.parse(clash_script_keyword_template));
|
||||
env.include_template("group_template", env.parse(clash_script_group_template));
|
||||
inja::Template tmpl = env.parse(clash_script_template);
|
||||
|
||||
try
|
||||
|
||||
Reference in new issue
Block a user