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

+77 -33
View File
@@ -19,6 +19,7 @@ ENDIF()
OPTION(USING_MALLOC_TRIM "Call malloc_trim after processing request to lower memory usage (Your system must support malloc_trim)." OFF) OPTION(USING_MALLOC_TRIM "Call malloc_trim after processing request to lower memory usage (Your system must support malloc_trim)." OFF)
#now using internal MD5 calculation #now using internal MD5 calculation
#OPTION(USING_MBEDTLS "Use mbedTLS instead of OpenSSL for MD5 calculation." OFF) #OPTION(USING_MBEDTLS "Use mbedTLS instead of OpenSSL for MD5 calculation." OFF)
OPTION(BUILD_STATIC_LIBRARY "Build a static library containing only the essential part." OFF)
INCLUDE(CheckCXXSourceCompiles) INCLUDE(CheckCXXSourceCompiles)
CHECK_CXX_SOURCE_COMPILES( CHECK_CXX_SOURCE_COMPILES(
@@ -28,14 +29,18 @@ void main(){std::to_string(0);}
" HAVE_TO_STRING) " HAVE_TO_STRING)
IF(HAVE_TO_STRING) IF(HAVE_TO_STRING)
ADD_DEFINITIONS(-DHAVE_TO_STRING) TARGET_COMPILE_DEFINITIONS(${BUILD_TARGET_NAME} -DHAVE_TO_STRING)
ENDIF() ENDIF()
IF(USING_MALLOC_TRIM) IF(USING_MALLOC_TRIM)
ADD_DEFINITIONS(-DMALLOC_TRIM) TARGET_COMPILE_DEFINITIONS(${BUILD_TARGET_NAME} -DMALLOC_TRIM)
ENDIF() ENDIF()
ADD_EXECUTABLE(subconverter SET(BUILD_TARGET_NAME ${PROJECT_NAME})
IF(NOT BUILD_STATIC_LIBRARY)
ADD_EXECUTABLE(${BUILD_TARGET_NAME}
src/generator/config/nodemanip.cpp src/generator/config/nodemanip.cpp
src/generator/config/ruleconvert.cpp src/generator/config/ruleconvert.cpp
src/generator/config/subexport.cpp src/generator/config/subexport.cpp
@@ -61,62 +66,101 @@ ADD_EXECUTABLE(subconverter
src/utils/string.cpp src/utils/string.cpp
src/utils/system.cpp src/utils/system.cpp
src/utils/urlencode.cpp) src/utils/urlencode.cpp)
INCLUDE_DIRECTORIES(src) TARGET_INCLUDE_DIRECTORIES(${BUILD_TARGET_NAME} src)
LINK_DIRECTORIES(${CMAKE_SOURCE_DIR}) LINK_DIRECTORIES(${CMAKE_SOURCE_DIR})
FIND_PACKAGE(PkgConfig REQUIRED) FIND_PACKAGE(PkgConfig REQUIRED)
SET(THREADS_PREFER_PTHREAD_FLAG ON) SET(THREADS_PREFER_PTHREAD_FLAG ON)
FIND_PACKAGE(Threads REQUIRED) FIND_PACKAGE(Threads REQUIRED)
TARGET_LINK_LIBRARIES(subconverter ${CMAKE_THREAD_LIBS_INIT}) TARGET_LINK_LIBRARIES(${BUILD_TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT})
PKG_CHECK_MODULES(LIBEVENT libevent>=2.1.10 REQUIRED) PKG_CHECK_MODULES(LIBEVENT libevent>=2.1.10 REQUIRED)
FIND_PATH(LIBEVENT_INCLUDE_DIR NAMES event.h PATHS ${LIBEVENT_INCLUDE_DIRS}) FIND_PATH(LIBEVENT_INCLUDE_DIR NAMES event.h PATHS ${LIBEVENT_INCLUDE_DIRS})
FIND_LIBRARY(LIBEVENT_LIBRARY NAMES event PATHS ${LIBEVENT_LIBRARY_DIRS}) FIND_LIBRARY(LIBEVENT_LIBRARY NAMES event PATHS ${LIBEVENT_LIBRARY_DIRS})
LINK_DIRECTORIES(${LIBEVENT_LIBRARY_DIRS}) TARGET_LINK_DIRECTORIES(${BUILD_TARGET_NAME} ${LIBEVENT_LIBRARY_DIRS})
INCLUDE_DIRECTORIES(${LIBEVENT_INCLUDE_DIR}) TARGET_INCLUDE_DIRECTORIES(${BUILD_TARGET_NAME} ${LIBEVENT_INCLUDE_DIR})
TARGET_LINK_LIBRARIES(subconverter ${LIBEVENT_LIBRARY}) TARGET_LINK_LIBRARIES(${BUILD_TARGET_NAME} ${LIBEVENT_LIBRARY})
FIND_PACKAGE(CURL 7.54.0 REQUIRED) FIND_PACKAGE(CURL 7.54.0 REQUIRED)
LINK_DIRECTORIES(${CURL_LIBRARY_DIRS}) TARGET_LINK_DIRECTORIES(${BUILD_TARGET_NAME} ${CURL_LIBRARY_DIRS})
INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIRS}) TARGET_INCLUDE_DIRECTORIES(${BUILD_TARGET_NAME} ${CURL_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(subconverter CURL::libcurl) TARGET_LINK_LIBRARIES(${BUILD_TARGET_NAME} CURL::libcurl)
ADD_DEFINITIONS(-DCURL_STATICLIB) TARGET_COMPILE_DEFINITIONS(${BUILD_TARGET_NAME} -DCURL_STATICLIB)
FIND_PACKAGE(Rapidjson REQUIRED) FIND_PACKAGE(Rapidjson REQUIRED)
INCLUDE_DIRECTORIES(${RAPIDJSON_INCLUDE_DIRS}) TARGET_INCLUDE_DIRECTORIES(${BUILD_TARGET_NAME} ${RAPIDJSON_INCLUDE_DIRS})
FIND_PACKAGE(toml11 REQUIRED) FIND_PACKAGE(toml11 REQUIRED)
INCLUDE_DIRECTORIES(${TOML11_INCLUDE_DIRS}) TARGET_INCLUDE_DIRECTORIES(${BUILD_TARGET_NAME} ${TOML11_INCLUDE_DIRS})
PKG_CHECK_MODULES(YAML_CPP yaml-cpp>=0.6.3 REQUIRED) PKG_CHECK_MODULES(YAML_CPP yaml-cpp>=0.6.3 REQUIRED)
FIND_LIBRARY(YAML_CPP_LIBRARY NAMES yaml-cpp yaml-cppd PATHS ${YAML_CPP_LIBRARY_DIRS}) FIND_LIBRARY(YAML_CPP_LIBRARY NAMES yaml-cpp yaml-cppd PATHS ${YAML_CPP_LIBRARY_DIRS})
LINK_DIRECTORIES(${YAML_CPP_LIBRARY_DIRS}) TARGET_LINK_DIRECTORIES(${BUILD_TARGET_NAME} ${YAML_CPP_LIBRARY_DIRS})
INCLUDE_DIRECTORIES(${YAML_CPP_INCLUDE_DIRS}) TARGET_INCLUDE_DIRECTORIES(${BUILD_TARGET_NAME} ${YAML_CPP_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(subconverter ${YAML_CPP_LIBRARY}) TARGET_LINK_LIBRARIES(${BUILD_TARGET_NAME} ${YAML_CPP_LIBRARY})
ADD_DEFINITIONS(-DYAML_CPP_STATIC_DEFINE) TARGET_COMPILE_DEFINITIONS(${BUILD_TARGET_NAME} -DYAML_CPP_STATIC_DEFINE)
#IF(USING_STD_REGEX STREQUAL "ON") FIND_PACKAGE(PCRE2 REQUIRED)
# ADD_DEFINITIONS(-DUSE_STD_REGEX) TARGET_INCLUDE_DIRECTORIES(${BUILD_TARGET_NAME} ${PCRE2_INCLUDE_DIRS})
#ELSE() TARGET_LINK_LIBRARIES(${BUILD_TARGET_NAME} ${PCRE2_LIBRARY})
FIND_PACKAGE(PCRE2 REQUIRED) TARGET_COMPILE_DEFINITIONS(${BUILD_TARGET_NAME} -DPCRE2_STATIC)
INCLUDE_DIRECTORIES(${PCRE2_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(subconverter ${PCRE2_LIBRARY})
ADD_DEFINITIONS(-DPCRE2_STATIC)
#ENDIF()
FIND_PACKAGE(QuickJS REQUIRED) FIND_PACKAGE(QuickJS REQUIRED)
INCLUDE_DIRECTORIES(${QUICKJS_INCLUDE_DIRS}) TARGET_INCLUDE_DIRECTORIES(${BUILD_TARGET_NAME} ${QUICKJS_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(subconverter ${QUICKJS_LIBRARIES}) TARGET_LINK_LIBRARIES(${BUILD_TARGET_NAME} ${QUICKJS_LIBRARIES})
FIND_PACKAGE(LibCron REQUIRED) FIND_PACKAGE(LibCron REQUIRED)
INCLUDE_DIRECTORIES(${LIBCRON_INCLUDE_DIRS}) TARGET_INCLUDE_DIRECTORIES(${BUILD_TARGET_NAME} ${LIBCRON_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(subconverter ${LIBCRON_LIBRARIES}) TARGET_LINK_LIBRARIES(${BUILD_TARGET_NAME} ${LIBCRON_LIBRARIES})
IF(WIN32) IF(WIN32)
TARGET_LINK_LIBRARIES(subconverter wsock32 ws2_32) TARGET_LINK_LIBRARIES(${BUILD_TARGET_NAME} wsock32 ws2_32)
ELSE() ELSE()
INCLUDE(GNUInstallDirs) INCLUDE(GNUInstallDirs)
INSTALL(TARGETS subconverter DESTINATION ${CMAKE_INSTALL_BINDIR}/subconverter) INSTALL(TARGETS ${BUILD_TARGET_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}/${BUILD_TARGET_NAME})
INSTALL(DIRECTORY base/ DESTINATION ${CMAKE_INSTALL_BINDIR}/subconverter FILES_MATCHING PATTERN "*") INSTALL(DIRECTORY base/ DESTINATION ${CMAKE_INSTALL_BINDIR}/${BUILD_TARGET_NAME} FILES_MATCHING PATTERN "*")
ENDIF()
ELSE()
ADD_LIBRARY(${BUILD_TARGET_NAME} STATIC
src/generator/config/ruleconvert.cpp
src/generator/config/subexport.cpp
src/generator/template/templates.cpp
src/lib/wrapper.cpp
src/parser/subparser.cpp
src/utils/base64/base64.cpp
src/utils/codepage.cpp
src/utils/logger.cpp
src/utils/md5/md5.cpp
src/utils/network.cpp
src/utils/regexp.cpp
src/utils/string.cpp
src/utils/urlencode.cpp)
TARGET_COMPILE_DEFINITIONS(${BUILD_TARGET_NAME} PRIVATE -DNO_JS_RUNTIME)
TARGET_INCLUDE_DIRECTORIES(${BUILD_TARGET_NAME} PUBLIC src)
FIND_PACKAGE(Rapidjson REQUIRED)
TARGET_INCLUDE_DIRECTORIES(${BUILD_TARGET_NAME} PRIVATE ${RAPIDJSON_INCLUDE_DIRS})
FIND_PACKAGE(PkgConfig REQUIRED)
PKG_CHECK_MODULES(YAML_CPP yaml-cpp>=0.6.3 REQUIRED)
FIND_LIBRARY(YAML_CPP_LIBRARY NAMES yaml-cpp yaml-cppd PATHS ${YAML_CPP_LIBRARY_DIRS})
TARGET_LINK_DIRECTORIES(${BUILD_TARGET_NAME} PRIVATE ${YAML_CPP_LIBRARY_DIRS})
TARGET_INCLUDE_DIRECTORIES(${BUILD_TARGET_NAME} PRIVATE ${YAML_CPP_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(${BUILD_TARGET_NAME} PRIVATE ${YAML_CPP_LIBRARY})
TARGET_COMPILE_DEFINITIONS(${BUILD_TARGET_NAME} PRIVATE -DYAML_CPP_STATIC_DEFINE)
FIND_PACKAGE(PCRE2 REQUIRED)
TARGET_INCLUDE_DIRECTORIES(${BUILD_TARGET_NAME} PRIVATE ${PCRE2_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(${BUILD_TARGET_NAME} PRIVATE ${PCRE2_LIBRARY})
TARGET_COMPILE_DEFINITIONS(${BUILD_TARGET_NAME} PRIVATE -DPCRE2_STATIC)
IF(WIN32)
TARGET_LINK_LIBRARIES(${BUILD_TARGET_NAME} PRIVATE ws2_32)
ENDIF()
ENDIF() ENDIF()
+132 -89
View File
@@ -20,6 +20,8 @@
extern Settings global; 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) int explodeConf(const std::string &filepath, std::vector<Proxy> &nodes)
{ {
return explodeConfContent(fileGet(filepath), 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."); 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, ","); std::string &remark = node.Remark, original_remark = node.Remark, returned_remark, real_rule;
bool match = false;
std::string range_begin_str, range_end_str; for(const RegexMatchConfig &x : rename_array)
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(regMatch(x, reg_num)) if(!x.Script.empty())
{ {
if(to_int(x, INT_MAX) == target) script_safe_runner(ext.js_runtime, ext.js_context, [&](qjs::Context &ctx)
match = true; {
} std::string script = x.Script;
else if(regMatch(x, reg_range)) if(startsWith(script, "path:"))
{ script = fileGet(script.substr(5), true);
/* try
range_begin = to_int(regReplace(x, reg_range, "$1"), INT_MAX); {
range_end = to_int(regReplace(x, reg_range, "$2"), INT_MIN); ctx.eval(script);
*/ auto rename = (std::function<std::string(const Proxy&)>) ctx.eval("rename");
regGetMatch(x, reg_range, 3, 0, &range_begin_str, &range_end_str); returned_remark = rename(node);
range_begin = to_int(range_begin_str, INT_MAX); if(!returned_remark.empty())
range_end = to_int(range_end_str, INT_MIN); remark = returned_remark;
if(target >= range_begin && target <= range_end) }
match = true; catch (qjs::exception)
} {
else if(regMatch(x, reg_not)) script_print_stack(ctx);
{ }
if(to_int(regReplace(x, reg_not, "$1"), INT_MAX) == target) }, global.scriptCleanContext);
match = false; continue;
}
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);
} }
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; char emoji_id[2] = {(char)-16, (char)-97};
static const std::string groupid_regex = R"(^!!(?:GROUPID|INSERT)=([\d\-+!,]+)(?:!!(.*))?$)", group_regex = R"(^!!(?:GROUP)=(.+?)(?:!!(.*))?$)"; std::string remark = orig_remark;
static const std::string type_regex = R"(^!!(?:TYPE)=(.+?)(?:!!(.*))?$)", port_regex = R"(^!!(?:PORT)=(.+?)(?:!!(.*))?$)", server_regex = R"(^!!(?:SERVER)=(.+?)(?:!!(.*))?$)"; while(true)
static const string_array types = {"", "SS", "SSR", "VMESS", "TROJAN", "SNELL", "HTTP", "HTTPS", "SOCKS5"};
if(startsWith(rule, "!!GROUP="))
{ {
regGetMatch(rule, group_regex, 3, 0, &target, &ret_real_rule); if(remark[0] == emoji_id[0] && remark[1] == emoji_id[1])
real_rule = ret_real_rule; remark.erase(0, 4);
return regFind(node.Group, target); 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 <string>
#include <vector> #include <vector>
#include <limits.h> #include <limits.h>
#ifndef NO_JS_RUNTIME
#include <quickjspp.hpp> #include <quickjspp.hpp>
#endif // NO_JS_RUNTIME
#include "../../config/regmatch.h" #include "../../config/regmatch.h"
#include "../../parser/config/proxy.h" #include "../../parser/config/proxy.h"
@@ -21,12 +24,15 @@ struct parse_settings
std::string *sub_info = nullptr; std::string *sub_info = nullptr;
bool authorized = false; bool authorized = false;
string_icase_map *request_header = nullptr; string_icase_map *request_header = nullptr;
#ifndef NO_JS_RUNTIME
qjs::Runtime *js_runtime = nullptr; qjs::Runtime *js_runtime = nullptr;
qjs::Context *js_context = 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); 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); 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); 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 #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(); 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; string_array vArray = split(range, ",");
bool match = false;
for(const RegexMatchConfig &x : rename_array) 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) if(to_int(x, INT_MAX) == target)
{ match = true;
std::string script = x.Script; }
if(startsWith(script, "path:")) else if(regMatch(x, reg_range))
script = fileGet(script.substr(5), true); {
try /*
{ range_begin = to_int(regReplace(x, reg_range, "$1"), INT_MAX);
ctx.eval(script); range_end = to_int(regReplace(x, reg_range, "$2"), INT_MIN);
auto rename = (std::function<std::string(const Proxy&)>) ctx.eval("rename"); */
returned_remark = rename(node); regGetMatch(x, reg_range, 3, 0, &range_begin_str, &range_end_str);
if(!returned_remark.empty()) range_begin = to_int(range_begin_str, INT_MAX);
remark = returned_remark; range_end = to_int(range_end_str, INT_MIN);
} if(target >= range_begin && target <= range_end)
catch (qjs::exception) match = true;
{ }
script_print_stack(ctx); else if(regMatch(x, reg_not))
} {
}, global.scriptCleanContext); if(to_int(regReplace(x, reg_not, "$1"), INT_MAX) == target)
continue; 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()) return match;
remark = original_remark;
return;
} }
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 target, ret_real_rule;
std::string remark = orig_remark; static const std::string groupid_regex = R"(^!!(?:GROUPID|INSERT)=([\d\-+!,]+)(?:!!(.*))?$)", group_regex = R"(^!!(?:GROUP)=(.+?)(?:!!(.*))?$)";
while(true) 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]) regGetMatch(rule, group_regex, 3, 0, &target, &ret_real_rule);
remark.erase(0, 4); real_rule = ret_real_rule;
else return regFind(node.Group, target);
break;
} }
if(remark.empty()) else if(startsWith(rule, "!!GROUPID=") || startsWith(rule, "!!INSERT="))
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()) int dir = startsWith(rule, "!!INSERT=") ? -1 : 1;
{ regGetMatch(rule, groupid_regex, 3, 0, &target, &ret_real_rule);
std::string result; real_rule = ret_real_rule;
script_safe_runner(ext.js_runtime, ext.js_context, [&](qjs::Context &ctx) return matchRange(target, dir * node.GroupId);
{
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; 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) 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)); filtered_nodelist.emplace_back(rule.substr(2));
} }
#ifndef NO_JS_RUNTIME
else if(startsWith(rule, "script:")) else if(startsWith(rule, "script:"))
{ {
script_safe_runner(ext.js_runtime, ext.js_context, [&](qjs::Context &ctx){ 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); }, global.scriptCleanContext);
} }
#endif // NO_JS_RUNTIME
else else
{ {
for(Proxy &x : nodelist) 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) 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; YAML::Node proxies, singleproxy, singlegroup, original_groups;
+8 -3
View File
@@ -3,7 +3,9 @@
#include <string> #include <string>
#ifndef NO_JS_RUNTIME
#include <quickjspp.hpp> #include <quickjspp.hpp>
#endif // NO_JS_RUNTIME
#include "../../config/proxygroup.h" #include "../../config/proxygroup.h"
#include "../../config/regmatch.h" #include "../../config/regmatch.h"
@@ -38,21 +40,24 @@ struct extra_settings
std::string sort_script = ""; std::string sort_script = "";
std::string clash_proxies_style = "flow"; std::string clash_proxies_style = "flow";
qjs::Runtime *js_runtime = nullptr;
qjs::Context *js_context = nullptr;
extra_settings() {}; extra_settings() {};
extra_settings(const extra_settings&) = delete; extra_settings(const extra_settings&) = delete;
extra_settings(extra_settings&&) = delete; extra_settings(extra_settings&&) = delete;
#ifndef NO_JS_RUNTIME
qjs::Runtime *js_runtime = nullptr;
qjs::Context *js_context = nullptr;
~extra_settings() ~extra_settings()
{ {
delete js_context; delete js_context;
delete js_runtime; 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 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 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); 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); 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/interfaces.h"
#include "../../handler/settings.h" #include "../../handler/settings.h"
#include "../../handler/webget.h"
#include "../../utils/logger.h" #include "../../utils/logger.h"
#include "../../utils/network.h" #include "../../utils/network.h"
#include "../../utils/regexp.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) int render_template(const std::string &content, const template_args &vars, std::string &output, const std::string &include_scope)
{ {
std::string absolute_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>()); return std::to_string(args.at(0)->get<int>());
}); });
#ifdef NO_WEBGET
env.add_callback("fetch", 1, template_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) env.set_include_callback([&](const std::string &name, const std::string &template_name)
{ {
+2 -38
View File
@@ -1307,49 +1307,13 @@ std::string getRewriteRemote(RESPONSE_CALLBACK_ARGS)
return output_content; return output_content;
} }
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;
}
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);
}
std::string jinja2_webGet(const std::string &url) std::string jinja2_webGet(const std::string &url)
{ {
std::string proxy = parseProxy(global.proxyConfig); std::string proxy = parseProxy(global.proxyConfig);
writeLog(0, "Template called fetch with url '" + url + "'.", LOG_LEVEL_INFO); writeLog(0, "Template called fetch with url '" + url + "'.", LOG_LEVEL_INFO);
return webGet(url, proxy, global.cacheConfig); return webGet(url, proxy, global.cacheConfig);
} }*/
inline std::string intToStream(unsigned long long stream) inline std::string intToStream(unsigned long long stream)
{ {
+2
View File
@@ -65,8 +65,10 @@ std::shared_future<std::string> fetchFileAsync(const std::string &path, const st
retVal = std::async(std::launch::async, [path](){return vfs::vfs_get(path);}); retVal = std::async(std::launch::async, [path](){return vfs::vfs_get(path);});
else */if(fileExist(path, true)) else */if(fileExist(path, true))
retVal = std::async(std::launch::async, [path](){return fileGet(path, true);}); retVal = std::async(std::launch::async, [path](){return fileGet(path, true);});
#ifdef NO_WEBGET
else if(isLink(path)) else if(isLink(path))
retVal = std::async(std::launch::async, [path, proxy, cache_ttl](){return webGet(path, proxy, cache_ttl);}); retVal = std::async(std::launch::async, [path, proxy, cache_ttl](){return webGet(path, proxy, cache_ttl);});
#endif // NO_WEBGET
else else
return std::async(std::launch::async, [](){return std::string();}); return std::async(std::launch::async, [](){return std::string();});
if(!async) if(!async)
+7
View File
@@ -0,0 +1,7 @@
#include "../handler/settings.h"
#include <string>
Settings global;
bool fileExist(const std::string&, bool) { return false; }
std::string fileGet(const std::string&, bool) { return std::string(); }
+9 -2
View File
@@ -1,11 +1,13 @@
#ifndef SCRIPT_QUICKJS_H_INCLUDED #ifndef SCRIPT_QUICKJS_H_INCLUDED
#define SCRIPT_QUICKJS_H_INCLUDED #define SCRIPT_QUICKJS_H_INCLUDED
#include <quickjspp.hpp>
#include "../parser/config/proxy.h" #include "../parser/config/proxy.h"
#include "../utils/defer.h" #include "../utils/defer.h"
#ifndef NO_JS_RUNTIME
#include <quickjspp.hpp>
void script_runtime_init(qjs::Runtime &runtime); void script_runtime_init(qjs::Runtime &runtime);
int script_context_init(qjs::Context &context); int script_context_init(qjs::Context &context);
int script_cleanup(qjs::Context &context); int script_cleanup(qjs::Context &context);
@@ -207,4 +209,9 @@ void script_safe_runner(qjs::Runtime *runtime, qjs::Context *context, Fn runnabl
runnable(*internal_context); runnable(*internal_context);
} }
#else
template <typename... Args>
void script_safe_runner(Args... args) { }
#endif // NO_JS_RUNTIME
#endif // SCRIPT_QUICKJS_H_INCLUDED #endif // SCRIPT_QUICKJS_H_INCLUDED