Add option to CMake to build as static library

This commit is contained in:
Tindy X committed 2021-12-15 00:13:00 +08:00
1 parent 4639ee483e
commit 35809391e9
10 files changed
+376 -294

No files matched your search

+132 -89
View File
@@ -20,6 +20,8 @@
extern Settings global;
bool applyMatcher(const std::string &rule, std::string &real_rule, const Proxy &node);
int explodeConf(const std::string &filepath, std::vector<Proxy> &nodes)
{
return explodeConfContent(fileGet(filepath), nodes);
@@ -372,103 +374,144 @@ void filterNodes(std::vector<Proxy> &nodes, string_array &exclude_remarks, strin
writeLog(LOG_TYPE_INFO, "Filter done.");
}
bool matchRange(const std::string &range, int target)
void nodeRename(Proxy &node, const RegexMatchConfigs &rename_array, extra_settings &ext)
{
string_array vArray = split(range, ",");
bool match = false;
std::string range_begin_str, range_end_str;
int range_begin, range_end;
static const std::string reg_num = "-?\\d+", reg_range = "(\\d+)-(\\d+)", reg_not = "\\!-?(\\d+)", reg_not_range = "\\!(\\d+)-(\\d+)", reg_less = "(\\d+)-", reg_more = "(\\d+)\\+";
for(std::string &x : vArray)
std::string &remark = node.Remark, original_remark = node.Remark, returned_remark, real_rule;
for(const RegexMatchConfig &x : rename_array)
{
if(regMatch(x, reg_num))
if(!x.Script.empty())
{
if(to_int(x, INT_MAX) == target)
match = true;
}
else if(regMatch(x, reg_range))
{
/*
range_begin = to_int(regReplace(x, reg_range, "$1"), INT_MAX);
range_end = to_int(regReplace(x, reg_range, "$2"), INT_MIN);
*/
regGetMatch(x, reg_range, 3, 0, &range_begin_str, &range_end_str);
range_begin = to_int(range_begin_str, INT_MAX);
range_end = to_int(range_end_str, INT_MIN);
if(target >= range_begin && target <= range_end)
match = true;
}
else if(regMatch(x, reg_not))
{
if(to_int(regReplace(x, reg_not, "$1"), INT_MAX) == target)
match = false;
}
else if(regMatch(x, reg_not_range))
{
/*
range_begin = to_int(regReplace(x, reg_range, "$1"), INT_MAX);
range_end = to_int(regReplace(x, reg_range, "$2"), INT_MIN);
*/
regGetMatch(x, reg_range, 3, 0, &range_begin_str, &range_end_str);
range_begin = to_int(range_begin_str, INT_MAX);
range_end = to_int(range_end_str, INT_MIN);
if(target >= range_begin && target <= range_end)
match = false;
}
else if(regMatch(x, reg_less))
{
if(to_int(regReplace(x, reg_less, "$1"), INT_MAX) >= target)
match = true;
}
else if(regMatch(x, reg_more))
{
if(to_int(regReplace(x, reg_more, "$1"), INT_MIN) <= target)
match = true;
script_safe_runner(ext.js_runtime, ext.js_context, [&](qjs::Context &ctx)
{
std::string script = x.Script;
if(startsWith(script, "path:"))
script = fileGet(script.substr(5), true);
try
{
ctx.eval(script);
auto rename = (std::function<std::string(const Proxy&)>) ctx.eval("rename");
returned_remark = rename(node);
if(!returned_remark.empty())
remark = returned_remark;
}
catch (qjs::exception)
{
script_print_stack(ctx);
}
}, global.scriptCleanContext);
continue;
}
if(applyMatcher(x.Match, real_rule, node) && real_rule.size())
remark = regReplace(remark, real_rule, x.Replace);
}
return match;
if(remark.empty())
remark = original_remark;
return;
}
bool applyMatcher(const std::string &rule, std::string &real_rule, const Proxy &node)
std::string removeEmoji(const std::string &orig_remark)
{
std::string target, ret_real_rule;
static const std::string groupid_regex = R"(^!!(?:GROUPID|INSERT)=([\d\-+!,]+)(?:!!(.*))?$)", group_regex = R"(^!!(?:GROUP)=(.+?)(?:!!(.*))?$)";
static const std::string type_regex = R"(^!!(?:TYPE)=(.+?)(?:!!(.*))?$)", port_regex = R"(^!!(?:PORT)=(.+?)(?:!!(.*))?$)", server_regex = R"(^!!(?:SERVER)=(.+?)(?:!!(.*))?$)";
static const string_array types = {"", "SS", "SSR", "VMESS", "TROJAN", "SNELL", "HTTP", "HTTPS", "SOCKS5"};
if(startsWith(rule, "!!GROUP="))
char emoji_id[2] = {(char)-16, (char)-97};
std::string remark = orig_remark;
while(true)
{
regGetMatch(rule, group_regex, 3, 0, &target, &ret_real_rule);
real_rule = ret_real_rule;
return regFind(node.Group, target);
if(remark[0] == emoji_id[0] && remark[1] == emoji_id[1])
remark.erase(0, 4);
else
break;
}
if(remark.empty())
return orig_remark;
return remark;
}
std::string addEmoji(const Proxy &node, const RegexMatchConfigs &emoji_array, extra_settings &ext)
{
std::string real_rule, ret;
for(const RegexMatchConfig &x : emoji_array)
{
if(!x.Script.empty())
{
std::string result;
script_safe_runner(ext.js_runtime, ext.js_context, [&](qjs::Context &ctx)
{
std::string script = x.Script;
if(startsWith(script, "path:"))
script = fileGet(script.substr(5), true);
try
{
ctx.eval(script);
auto getEmoji = (std::function<std::string(const Proxy&)>) ctx.eval("getEmoji");
ret = getEmoji(node);
if(!ret.empty())
result = ret + " " + node.Remark;
}
catch (qjs::exception)
{
script_print_stack(ctx);
}
}, global.scriptCleanContext);
if(!result.empty())
return result;
continue;
}
if(x.Replace.empty())
continue;
if(applyMatcher(x.Match, real_rule, node) && real_rule.size() && regFind(node.Remark, real_rule))
return x.Replace + " " + node.Remark;
}
return node.Remark;
}
void preprocessNodes(std::vector<Proxy> &nodes, extra_settings &ext)
{
std::for_each(nodes.begin(), nodes.end(), [&ext](Proxy &x)
{
if(ext.remove_emoji)
x.Remark = trim(removeEmoji(x.Remark));
nodeRename(x, ext.rename_array, ext);
if(ext.add_emoji)
x.Remark = addEmoji(x, ext.emoji_array, ext);
});
if(ext.sort_flag)
{
bool failed = true;
if(ext.sort_script.size())
{
std::string script = ext.sort_script;
if(startsWith(script, "path:"))
script = fileGet(script.substr(5), false);
script_safe_runner(ext.js_runtime, ext.js_context, [&](qjs::Context &ctx)
{
try
{
ctx.eval(script);
auto compare = (std::function<int(const Proxy&, const Proxy&)>) ctx.eval("compare");
auto comparer = [&](const Proxy &a, const Proxy &b)
{
if(a.Type == ProxyType::Unknow)
return 1;
if(b.Type == ProxyType::Unknow)
return 0;
return compare(a, b);
};
std::stable_sort(nodes.begin(), nodes.end(), comparer);
failed = false;
}
catch(qjs::exception)
{
script_print_stack(ctx);
}
}, global.scriptCleanContext);
}
if(failed) std::stable_sort(nodes.begin(), nodes.end(), [](const Proxy &a, const Proxy &b)
{
return a.Remark < b.Remark;
});
}
else if(startsWith(rule, "!!GROUPID=") || startsWith(rule, "!!INSERT="))
{
int dir = startsWith(rule, "!!INSERT=") ? -1 : 1;
regGetMatch(rule, groupid_regex, 3, 0, &target, &ret_real_rule);
real_rule = ret_real_rule;
return matchRange(target, dir * node.GroupId);
}
else if(startsWith(rule, "!!TYPE="))
{
regGetMatch(rule, type_regex, 3, 0, &target, &ret_real_rule);
real_rule = ret_real_rule;
if(node.Type == ProxyType::Unknow)
return false;
return regMatch(types[node.Type], target);
}
else if(startsWith(rule, "!!PORT="))
{
regGetMatch(rule, port_regex, 3, 0, &target, &ret_real_rule);
real_rule = ret_real_rule;
return matchRange(target, node.Port);
}
else if(startsWith(rule, "!!SERVER="))
{
regGetMatch(rule, server_regex, 3, 0, &target, &ret_real_rule);
real_rule = ret_real_rule;
return regFind(node.Hostname, target);
}
else
real_rule = rule;
return true;
}
+6
View File
@@ -4,7 +4,10 @@
#include <string>
#include <vector>
#include <limits.h>
#ifndef NO_JS_RUNTIME
#include <quickjspp.hpp>
#endif // NO_JS_RUNTIME
#include "../../config/regmatch.h"
#include "../../parser/config/proxy.h"
@@ -21,12 +24,15 @@ struct parse_settings
std::string *sub_info = nullptr;
bool authorized = false;
string_icase_map *request_header = nullptr;
#ifndef NO_JS_RUNTIME
qjs::Runtime *js_runtime = nullptr;
qjs::Context *js_context = nullptr;
#endif // NO_JS_RUNTIME
};
int addNodes(std::string link, std::vector<Proxy> &allNodes, int groupID, parse_settings &parse_set);
void filterNodes(std::vector<Proxy> &nodes, string_array &exclude_remarks, string_array &include_remarks, int groupID);
bool applyMatcher(const std::string &rule, std::string &real_rule, const Proxy &node);
void preprocessNodes(std::vector<Proxy> &nodes, extra_settings &ext);
#endif // NODEMANIP_H_INCLUDED
+89 -128
View File
@@ -64,95 +64,105 @@ std::string vmessLinkConstruct(const std::string &remarks, const std::string &ad
return sb.GetString();
}
void nodeRename(Proxy &node, const RegexMatchConfigs &rename_array, extra_settings &ext)
bool matchRange(const std::string &range, int target)
{
std::string &remark = node.Remark, original_remark = node.Remark, returned_remark, real_rule;
for(const RegexMatchConfig &x : rename_array)
string_array vArray = split(range, ",");
bool match = false;
std::string range_begin_str, range_end_str;
int range_begin, range_end;
static const std::string reg_num = "-?\\d+", reg_range = "(\\d+)-(\\d+)", reg_not = "\\!-?(\\d+)", reg_not_range = "\\!(\\d+)-(\\d+)", reg_less = "(\\d+)-", reg_more = "(\\d+)\\+";
for(std::string &x : vArray)
{
if(!x.Script.empty())
if(regMatch(x, reg_num))
{
script_safe_runner(ext.js_runtime, ext.js_context, [&](qjs::Context &ctx)
{
std::string script = x.Script;
if(startsWith(script, "path:"))
script = fileGet(script.substr(5), true);
try
{
ctx.eval(script);
auto rename = (std::function<std::string(const Proxy&)>) ctx.eval("rename");
returned_remark = rename(node);
if(!returned_remark.empty())
remark = returned_remark;
}
catch (qjs::exception)
{
script_print_stack(ctx);
}
}, global.scriptCleanContext);
continue;
if(to_int(x, INT_MAX) == target)
match = true;
}
else if(regMatch(x, reg_range))
{
/*
range_begin = to_int(regReplace(x, reg_range, "$1"), INT_MAX);
range_end = to_int(regReplace(x, reg_range, "$2"), INT_MIN);
*/
regGetMatch(x, reg_range, 3, 0, &range_begin_str, &range_end_str);
range_begin = to_int(range_begin_str, INT_MAX);
range_end = to_int(range_end_str, INT_MIN);
if(target >= range_begin && target <= range_end)
match = true;
}
else if(regMatch(x, reg_not))
{
if(to_int(regReplace(x, reg_not, "$1"), INT_MAX) == target)
match = false;
}
else if(regMatch(x, reg_not_range))
{
/*
range_begin = to_int(regReplace(x, reg_range, "$1"), INT_MAX);
range_end = to_int(regReplace(x, reg_range, "$2"), INT_MIN);
*/
regGetMatch(x, reg_range, 3, 0, &range_begin_str, &range_end_str);
range_begin = to_int(range_begin_str, INT_MAX);
range_end = to_int(range_end_str, INT_MIN);
if(target >= range_begin && target <= range_end)
match = false;
}
else if(regMatch(x, reg_less))
{
if(to_int(regReplace(x, reg_less, "$1"), INT_MAX) >= target)
match = true;
}
else if(regMatch(x, reg_more))
{
if(to_int(regReplace(x, reg_more, "$1"), INT_MIN) <= target)
match = true;
}
if(applyMatcher(x.Match, real_rule, node) && real_rule.size())
remark = regReplace(remark, real_rule, x.Replace);
}
if(remark.empty())
remark = original_remark;
return;
return match;
}
std::string removeEmoji(const std::string &orig_remark)
bool applyMatcher(const std::string &rule, std::string &real_rule, const Proxy &node)
{
char emoji_id[2] = {(char)-16, (char)-97};
std::string remark = orig_remark;
while(true)
std::string target, ret_real_rule;
static const std::string groupid_regex = R"(^!!(?:GROUPID|INSERT)=([\d\-+!,]+)(?:!!(.*))?$)", group_regex = R"(^!!(?:GROUP)=(.+?)(?:!!(.*))?$)";
static const std::string type_regex = R"(^!!(?:TYPE)=(.+?)(?:!!(.*))?$)", port_regex = R"(^!!(?:PORT)=(.+?)(?:!!(.*))?$)", server_regex = R"(^!!(?:SERVER)=(.+?)(?:!!(.*))?$)";
static const string_array types = {"", "SS", "SSR", "VMESS", "TROJAN", "SNELL", "HTTP", "HTTPS", "SOCKS5"};
if(startsWith(rule, "!!GROUP="))
{
if(remark[0] == emoji_id[0] && remark[1] == emoji_id[1])
remark.erase(0, 4);
else
break;
regGetMatch(rule, group_regex, 3, 0, &target, &ret_real_rule);
real_rule = ret_real_rule;
return regFind(node.Group, target);
}
if(remark.empty())
return orig_remark;
return remark;
}
std::string addEmoji(const Proxy &node, const RegexMatchConfigs &emoji_array, extra_settings &ext)
{
std::string real_rule, ret;
for(const RegexMatchConfig &x : emoji_array)
else if(startsWith(rule, "!!GROUPID=") || startsWith(rule, "!!INSERT="))
{
if(!x.Script.empty())
{
std::string result;
script_safe_runner(ext.js_runtime, ext.js_context, [&](qjs::Context &ctx)
{
std::string script = x.Script;
if(startsWith(script, "path:"))
script = fileGet(script.substr(5), true);
try
{
ctx.eval(script);
auto getEmoji = (std::function<std::string(const Proxy&)>) ctx.eval("getEmoji");
ret = getEmoji(node);
if(!ret.empty())
result = ret + " " + node.Remark;
}
catch (qjs::exception)
{
script_print_stack(ctx);
}
}, global.scriptCleanContext);
if(!result.empty())
return result;
continue;
}
if(x.Replace.empty())
continue;
if(applyMatcher(x.Match, real_rule, node) && real_rule.size() && regFind(node.Remark, real_rule))
return x.Replace + " " + node.Remark;
int dir = startsWith(rule, "!!INSERT=") ? -1 : 1;
regGetMatch(rule, groupid_regex, 3, 0, &target, &ret_real_rule);
real_rule = ret_real_rule;
return matchRange(target, dir * node.GroupId);
}
return node.Remark;
else if(startsWith(rule, "!!TYPE="))
{
regGetMatch(rule, type_regex, 3, 0, &target, &ret_real_rule);
real_rule = ret_real_rule;
if(node.Type == ProxyType::Unknow)
return false;
return regMatch(types[node.Type], target);
}
else if(startsWith(rule, "!!PORT="))
{
regGetMatch(rule, port_regex, 3, 0, &target, &ret_real_rule);
real_rule = ret_real_rule;
return matchRange(target, node.Port);
}
else if(startsWith(rule, "!!SERVER="))
{
regGetMatch(rule, server_regex, 3, 0, &target, &ret_real_rule);
real_rule = ret_real_rule;
return regFind(node.Hostname, target);
}
else
real_rule = rule;
return true;
}
void processRemark(std::string &oldremark, std::string &newremark, string_array &remarks_list, bool proc_comma = true)
@@ -182,6 +192,7 @@ void groupGenerate(const std::string &rule, std::vector<Proxy> &nodelist, string
{
filtered_nodelist.emplace_back(rule.substr(2));
}
#ifndef NO_JS_RUNTIME
else if(startsWith(rule, "script:"))
{
script_safe_runner(ext.js_runtime, ext.js_context, [&](qjs::Context &ctx){
@@ -199,6 +210,7 @@ void groupGenerate(const std::string &rule, std::vector<Proxy> &nodelist, string
}
}, global.scriptCleanContext);
}
#endif // NO_JS_RUNTIME
else
{
for(Proxy &x : nodelist)
@@ -209,57 +221,6 @@ void groupGenerate(const std::string &rule, std::vector<Proxy> &nodelist, string
}
}
void preprocessNodes(std::vector<Proxy> &nodes, extra_settings &ext)
{
std::for_each(nodes.begin(), nodes.end(), [&ext](Proxy &x)
{
if(ext.remove_emoji)
x.Remark = trim(removeEmoji(x.Remark));
nodeRename(x, ext.rename_array, ext);
if(ext.add_emoji)
x.Remark = addEmoji(x, ext.emoji_array, ext);
});
if(ext.sort_flag)
{
bool failed = true;
if(ext.sort_script.size())
{
std::string script = ext.sort_script;
if(startsWith(script, "path:"))
script = fileGet(script.substr(5), false);
script_safe_runner(ext.js_runtime, ext.js_context, [&](qjs::Context &ctx)
{
try
{
ctx.eval(script);
auto compare = (std::function<int(const Proxy&, const Proxy&)>) ctx.eval("compare");
auto comparer = [&](const Proxy &a, const Proxy &b)
{
if(a.Type == ProxyType::Unknow)
return 1;
if(b.Type == ProxyType::Unknow)
return 0;
return compare(a, b);
};
std::stable_sort(nodes.begin(), nodes.end(), comparer);
failed = false;
}
catch(qjs::exception)
{
script_print_stack(ctx);
}
}, global.scriptCleanContext);
}
if(failed) std::stable_sort(nodes.begin(), nodes.end(), [](const Proxy &a, const Proxy &b)
{
return a.Remark < b.Remark;
});
}
}
void proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupConfigs &extra_proxy_group, bool clashR, extra_settings &ext)
{
YAML::Node proxies, singleproxy, singlegroup, original_groups;
+8 -3
View File
@@ -3,7 +3,9 @@
#include <string>
#ifndef NO_JS_RUNTIME
#include <quickjspp.hpp>
#endif // NO_JS_RUNTIME
#include "../../config/proxygroup.h"
#include "../../config/regmatch.h"
@@ -38,21 +40,24 @@ struct extra_settings
std::string sort_script = "";
std::string clash_proxies_style = "flow";
qjs::Runtime *js_runtime = nullptr;
qjs::Context *js_context = nullptr;
extra_settings() {};
extra_settings(const extra_settings&) = delete;
extra_settings(extra_settings&&) = delete;
#ifndef NO_JS_RUNTIME
qjs::Runtime *js_runtime = nullptr;
qjs::Context *js_context = nullptr;
~extra_settings()
{
delete js_context;
delete js_runtime;
}
#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);
void preprocessNodes(std::vector<Proxy> &nodes, extra_settings &ext);
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);
+44 -1
View File
@@ -7,6 +7,7 @@
#include "../../handler/interfaces.h"
#include "../../handler/settings.h"
#include "../../handler/webget.h"
#include "../../utils/logger.h"
#include "../../utils/network.h"
#include "../../utils/regexp.h"
@@ -36,6 +37,46 @@ static inline void parse_json_pointer(nlohmann::json &json, const std::string &p
}
}
/*
std::string parseHostname(inja::Arguments &args)
{
std::string data = args.at(0)->get<std::string>(), hostname;
const std::string matcher = R"(^(?i:hostname\s*?=\s*?)(.*?)\s$)";
string_array urls = split(data, ",");
if(!urls.size())
return std::string();
std::string input_content, output_content, proxy = parseProxy(global.proxyConfig);
for(std::string &x : urls)
{
input_content = webGet(x, proxy, global.cacheConfig);
regGetMatch(input_content, matcher, 2, 0, &hostname);
if(hostname.size())
{
output_content += hostname + ",";
hostname.clear();
}
}
string_array vArray = split(output_content, ",");
std::set<std::string> hostnames;
for(std::string &x : vArray)
hostnames.emplace(trim(x));
output_content = std::accumulate(hostnames.begin(), hostnames.end(), std::string(), [](std::string a, std::string b)
{
return std::move(a) + "," + std::move(b);
});
return output_content;
}*/
#ifndef NO_WEBGET
std::string template_webGet(inja::Arguments &args)
{
std::string data = args.at(0)->get<std::string>(), proxy = parseProxy(global.proxyConfig);
writeLog(0, "Template called fetch with url '" + data + "'.", LOG_LEVEL_INFO);
return webGet(data, proxy, global.cacheConfig);
}
#endif // NO_WEBGET
int render_template(const std::string &content, const template_args &vars, std::string &output, const std::string &include_scope)
{
std::string absolute_scope;
@@ -179,8 +220,10 @@ int render_template(const std::string &content, const template_args &vars, std::
{
return std::to_string(args.at(0)->get<int>());
});
#ifdef NO_WEBGET
env.add_callback("fetch", 1, template_webGet);
env.add_callback("parseHostname", 1, parseHostname);
#endif // NO_WEBGET
//env.add_callback("parseHostname", 1, parseHostname);
env.set_include_callback([&](const std::string &name, const std::string &template_name)
{