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:
Tindy X committed 2020-07-06 03:34:08 +08:00
1 parent 5c9bb44054
commit 1ca88d9e31
7 files changed
+204 -152

No files matched your search

+4 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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 &section)
{
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 &section, 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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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