Enhancements

Add Subscription-UserInfo header to exporter, supports extracting from original headers and from info nodes.
Optimize codes.
This commit is contained in:
Tindy X committed 2020-01-30 17:14:00 +08:00
1 parent 7c546e9606
commit 4492fcd806
10 files changed
+365 -114

No files matched your search

+15
View File
@@ -35,6 +35,21 @@ proxy_subscription=NONE
;Append a proxy type string ([SS] [SSR] [VMess]) to node remark. ;Append a proxy type string ([SS] [SSR] [VMess]) to node remark.
append_proxy_type=false append_proxy_type=false
[userinfo]
;Rules to extract stream data from node
;Format: full_match_regex|new_format_regex
;where new_format_regex should be like "total=$1&left=$2&used=$3"
stream_rule=^剩余流量:(.*?) (.*)$|total=$1&left=$2
stream_rule=^Bandwidth: (.*?)/(.*)$|used=$1&total=$2
stream_rule=^\[.*?\]剩余(.*?)@(?:.*)$|total=$1
;Rules to extract expire time data from node
;Format: full_match_regex|new_format_regex
;where new_format_regex should follow this example: yyyy:mm:dd:hh:mm:ss
time_rule=^过期时间:(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)$|$1:$2:$3:$4:$5:$6
time_rule=^到期时间:(\d+)-(\d+)-(\d+)$|$1:$2:$3:0:0:0
time_rule=^Smart Access expire: (\d+)/(\d+)/(\d+)$|$1:$2:$3:0:0:0
[node_pref] [node_pref]
udp_flag=false udp_flag=false
tcp_fast_open_flag=false tcp_fast_open_flag=false
+26 -16
View File
@@ -9,12 +9,15 @@
#include "misc.h" #include "misc.h"
#define INIREADER_EXCEPTION_NONE 0 enum
#define INIREADER_EXCEPTION_EMPTY -1 {
#define INIREADER_EXCEPTION_DUPLICATE -2 INIREADER_EXCEPTION_EMPTY = -5,
#define INIREADER_EXCEPTION_OUTOFBOUND -3 INIREADER_EXCEPTION_DUPLICATE,
#define INIREADER_EXCEPTION_NOTEXIST -4 INIREADER_EXCEPTION_OUTOFBOUND,
#define INIREADER_EXCEPTION_NOTPARSED -5 INIREADER_EXCEPTION_NOTEXIST,
INIREADER_EXCEPTION_NOTPARSED,
INIREADER_EXCEPTION_NONE
};
#define __SAVE_ERROR_AND_RETURN(x) {last_error = x; return last_error;} #define __SAVE_ERROR_AND_RETURN(x) {last_error = x; return last_error;}
@@ -80,6 +83,11 @@ public:
*/ */
bool allow_dup_section_titles = false; bool allow_dup_section_titles = false;
/**
* @brief Keep an empty section while parsing
*/
bool keep_empty_section = true;
/** /**
* @brief Initialize the reader. * @brief Initialize the reader.
*/ */
@@ -224,23 +232,24 @@ public:
thisSection = strLine.substr(1, lineSize - 2); //save section title thisSection = strLine.substr(1, lineSize - 2); //save section title
inExcludedSection = chkIgnore(thisSection); //check if this section is excluded inExcludedSection = chkIgnore(thisSection); //check if this section is excluded
if(curSection.size() && itemGroup.size()) //just finished reading a section 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.count(curSection)) //a section with the same name has been inserted
{ {
if(allow_dup_section_titles) if(allow_dup_section_titles || !ini_content.at(curSection).size())
{ {
eraseElements(existItemGroup); eraseElements(existItemGroup);
existItemGroup = ini_content.at(curSection); //get the old items existItemGroup = ini_content.at(curSection); //get the old items
for(auto &x : existItemGroup) for(auto &x : existItemGroup)
itemGroup.emplace(x); //insert them all into new section itemGroup.emplace(x); //insert them all into new section
ini_content.erase(curSection); //remove the old section
} }
else else if(ini_content.at(curSection).size())
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_DUPLICATE); //not allowed, stop __SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_DUPLICATE); //not allowed, stop
ini_content.erase(curSection); //remove the old section
} }
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 ini_content.emplace(curSection, itemGroup); //insert previous section to content map
read_sections.push_back(curSection); //add to read sections list
if(std::count(section_order.cbegin(), section_order.cend(), curSection) == 0) if(std::count(section_order.cbegin(), section_order.cend(), curSection) == 0)
section_order.emplace_back(curSection); section_order.emplace_back(curSection);
} }
@@ -255,7 +264,7 @@ public:
if(include_sections.size() && include_sections == read_sections) //all included sections has been read if(include_sections.size() && include_sections == read_sections) //all included sections has been read
break; //exit now break; //exit now
} }
if(curSection.size() && itemGroup.size()) //final section 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.count(curSection)) //a section with the same name has been inserted
{ {
@@ -265,13 +274,14 @@ public:
existItemGroup = ini_content.at(curSection); //get the old items existItemGroup = ini_content.at(curSection); //get the old items
for(auto &x : existItemGroup) for(auto &x : existItemGroup)
itemGroup.emplace(x); //insert them all into new section itemGroup.emplace(x); //insert them all into new section
ini_content.erase(curSection); //remove the old section
} }
else else if(ini_content.at(curSection).size())
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_DUPLICATE); //not allowed, stop __SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_DUPLICATE); //not allowed, stop
ini_content.erase(curSection); //remove the old section
} }
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 ini_content.emplace(curSection, itemGroup); //insert this section to content map
read_sections.emplace_back(curSection); //add to read sections list
if(std::count(section_order.cbegin(), section_order.cend(), curSection) == 0) if(std::count(section_order.cbegin(), section_order.cend(), curSection) == 0)
section_order.emplace_back(curSection); section_order.emplace_back(curSection);
} }
@@ -803,7 +813,7 @@ public:
content += "\n"; content += "\n";
} }
return content.substr(0, content.size() - 2); return content.erase(content.size() - 2);
} }
/** /**
+49 -10
View File
@@ -20,7 +20,7 @@
//common settings //common settings
std::string pref_path = "pref.ini"; std::string pref_path = "pref.ini";
bool generator_mode = false; bool generator_mode = false;
string_array def_exclude_remarks, def_include_remarks, rulesets; string_array def_exclude_remarks, def_include_remarks, rulesets, stream_rules, time_rules;
std::vector<ruleset_content> ruleset_content_array; std::vector<ruleset_content> ruleset_content_array;
std::string listen_address = "127.0.0.1", default_url, managed_config_prefix; std::string listen_address = "127.0.0.1", default_url, managed_config_prefix;
int listen_port = 25500, max_pending_connections = 10, max_concurrent_threads = 4; int listen_port = 25500, max_pending_connections = 10, max_concurrent_threads = 4;
@@ -151,7 +151,7 @@ void readConf()
eraseElements(def_include_remarks); eraseElements(def_include_remarks);
eraseElements(clash_extra_group); eraseElements(clash_extra_group);
eraseElements(rulesets); eraseElements(rulesets);
string_array emojis_temp, renames_temp; string_array tempArray;
ini.EnterSection("common"); ini.EnterSection("common");
if(ini.ItemExist("api_mode")) if(ini.ItemExist("api_mode"))
@@ -201,8 +201,26 @@ void readConf()
filter_deprecated = ini.GetBool("filter_deprecated_nodes"); filter_deprecated = ini.GetBool("filter_deprecated_nodes");
if(ini.ItemPrefixExist("rename_node")) if(ini.ItemPrefixExist("rename_node"))
{ {
ini.GetAll("rename_node", renames_temp); ini.GetAll("rename_node", tempArray);
safe_set_renames(renames_temp); safe_set_renames(tempArray);
eraseElements(tempArray);
}
}
if(ini.SectionExist("userinfo"))
{
ini.EnterSection("userinfo");
if(ini.ItemPrefixExist("stream_rule"))
{
ini.GetAll("stream_rule", tempArray);
safe_set_streams(tempArray);
eraseElements(tempArray);
}
if(ini.ItemPrefixExist("time_rule"))
{
ini.GetAll("time_rule", tempArray);
safe_set_times(tempArray);
eraseElements(tempArray);
} }
} }
@@ -219,8 +237,9 @@ void readConf()
remove_old_emoji = ini.GetBool("remove_old_emoji"); remove_old_emoji = ini.GetBool("remove_old_emoji");
if(ini.ItemPrefixExist("rule")) if(ini.ItemPrefixExist("rule"))
{ {
ini.GetAll("rule", emojis_temp); ini.GetAll("rule", tempArray);
safe_set_emojis(emojis_temp); safe_set_emojis(tempArray);
eraseElements(tempArray);
} }
ini.EnterSection("ruleset"); ini.EnterSection("ruleset");
@@ -284,6 +303,7 @@ int loadExternalConfig(std::string &path, ExternalConfig &ext, std::string proxy
INIReader ini; INIReader ini;
ini.store_isolated_line = true; ini.store_isolated_line = true;
ini.keep_empty_section = false;
ini.SetIsolatedItemsSection("custom"); ini.SetIsolatedItemsSection("custom");
if(ini.Parse(base_content) != INIREADER_EXCEPTION_NONE) if(ini.Parse(base_content) != INIREADER_EXCEPTION_NONE)
{ {
@@ -361,6 +381,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
std::string groups = urlsafe_base64_decode(getUrlArg(argument, "groups")), ruleset = urlsafe_base64_decode(getUrlArg(argument, "ruleset")), config = UrlDecode(getUrlArg(argument, "config")); std::string groups = urlsafe_base64_decode(getUrlArg(argument, "groups")), ruleset = urlsafe_base64_decode(getUrlArg(argument, "ruleset")), config = UrlDecode(getUrlArg(argument, "config"));
std::vector<ruleset_content> rca; std::vector<ruleset_content> rca;
extra_settings ext; extra_settings ext;
std::string subInfo;
if(std::find(regex_blacklist.cbegin(), regex_blacklist.cend(), include) != regex_blacklist.cend() || std::find(regex_blacklist.cbegin(), regex_blacklist.cend(), exclude) != regex_blacklist.cend()) if(std::find(regex_blacklist.cbegin(), regex_blacklist.cend(), include) != regex_blacklist.cend() || std::find(regex_blacklist.cbegin(), regex_blacklist.cend(), exclude) != regex_blacklist.cend())
return "Invalid request!"; return "Invalid request!";
@@ -512,11 +533,12 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
custom_group = group; custom_group = group;
//start parsing urls //start parsing urls
string_array stream_temp = safe_get_streams(), time_temp = safe_get_times();
for(std::string &x : urls) for(std::string &x : urls)
{ {
x = trim(x); x = trim(x);
std::cerr<<"Fetching node data from url '"<<x<<"'."<<std::endl; std::cerr<<"Fetching node data from url '"<<x<<"'."<<std::endl;
if(addNodes(x, nodes, groupID, proxy, exclude_remarks, include_remarks) == -1) if(addNodes(x, nodes, groupID, proxy, exclude_remarks, include_remarks, stream_temp, time_temp, subInfo) == -1)
{ {
*status_code = 400; *status_code = 400;
return std::string("The following link doesn't contain any valid node info: " + x); return std::string("The following link doesn't contain any valid node info: " + x);
@@ -530,6 +552,9 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
return "No nodes were found!"; return "No nodes were found!";
} }
if(subInfo.size() && groupID == 1)
extra_headers.emplace("Subscription-UserInfo", subInfo);
std::cerr<<"Generate target: "; std::cerr<<"Generate target: ";
if(target == "clash" || target == "clashr") if(target == "clash" || target == "clashr")
{ {
@@ -672,6 +697,7 @@ std::string simpleToClashR(RESPONSE_CALLBACK_ARGS)
std::vector<nodeInfo> nodes; std::vector<nodeInfo> nodes;
string_array extra_group, extra_ruleset, include_remarks, exclude_remarks; string_array extra_group, extra_ruleset, include_remarks, exclude_remarks;
std::vector<ruleset_content> rca; std::vector<ruleset_content> rca;
std::string subInfo;
if(!url.size()) if(!url.size())
url = default_url; url = default_url;
@@ -707,9 +733,22 @@ std::string simpleToClashR(RESPONSE_CALLBACK_ARGS)
include_remarks = def_include_remarks; include_remarks = def_include_remarks;
exclude_remarks = def_exclude_remarks; exclude_remarks = def_exclude_remarks;
std::cerr<<"Fetching node data from url '"<<url<<"'.\n"; //start parsing urls
addNodes(url, nodes, 0, proxy, exclude_remarks, include_remarks); int groupID = 0;
string_array dummy;
string_array urls = split(url, "|");
for(std::string &x : urls)
{
x = trim(x);
std::cerr<<"Fetching node data from url '"<<x<<"'."<<std::endl;
if(addNodes(x, nodes, groupID, proxy, exclude_remarks, include_remarks, dummy, dummy, subInfo) == -1)
{
*status_code = 400;
return std::string("The following link doesn't contain any valid node info: " + x);
}
groupID++;
}
//exit if found nothing
if(!nodes.size()) if(!nodes.size())
{ {
*status_code = 400; *status_code = 400;
+26 -1
View File
@@ -4,9 +4,10 @@
//safety lock for multi-thread //safety lock for multi-thread
typedef std::lock_guard<std::mutex> guarded_mutex; typedef std::lock_guard<std::mutex> guarded_mutex;
std::mutex on_configuring, on_emoji, on_rename; std::mutex on_configuring, on_emoji, on_rename, on_stream, on_time;
extern string_array emojis, renames; extern string_array emojis, renames;
extern string_array stream_rules, time_rules;
string_array safe_get_emojis() string_array safe_get_emojis()
{ {
@@ -20,6 +21,18 @@ string_array safe_get_renames()
return renames; return renames;
} }
string_array safe_get_streams()
{
guarded_mutex guard(on_stream);
return stream_rules;
}
string_array safe_get_times()
{
guarded_mutex guard(on_time);
return time_rules;
}
void safe_set_emojis(string_array &data) void safe_set_emojis(string_array &data)
{ {
guarded_mutex guard(on_emoji); guarded_mutex guard(on_emoji);
@@ -31,3 +44,15 @@ void safe_set_renames(string_array &data)
guarded_mutex guard(on_rename); guarded_mutex guard(on_rename);
renames.swap(data); renames.swap(data);
} }
void safe_set_streams(string_array &data)
{
guarded_mutex guard(on_stream);
stream_rules.swap(data);
}
void safe_set_times(string_array &data)
{
guarded_mutex guard(on_time);
time_rules.swap(data);
}
+4 -3
View File
@@ -6,12 +6,13 @@
typedef std::lock_guard<std::mutex> guarded_mutex; typedef std::lock_guard<std::mutex> guarded_mutex;
void try_config_lock();
void try_emoji_lock();
void try_rename_lock();
string_array safe_get_emojis(); string_array safe_get_emojis();
string_array safe_get_renames(); string_array safe_get_renames();
string_array safe_get_streams();
string_array safe_get_times();
void safe_set_emojis(string_array &data); void safe_set_emojis(string_array &data);
void safe_set_renames(string_array &data); void safe_set_renames(string_array &data);
void safe_set_streams(string_array &data);
void safe_set_times(string_array &data);
#endif // MULTITHREAD_H_INCLUDED #endif // MULTITHREAD_H_INCLUDED
+10 -5
View File
@@ -22,12 +22,12 @@ void copyNodes(std::vector<nodeInfo> &source, std::vector<nodeInfo> &dest)
} }
} }
int addNodes(std::string link, std::vector<nodeInfo> &allNodes, int groupID, std::string proxy, string_array &exclude_remarks, string_array &include_remarks) int addNodes(std::string link, std::vector<nodeInfo> &allNodes, int groupID, std::string proxy, string_array &exclude_remarks, string_array &include_remarks, string_array &stream_rules, string_array &time_rules, std::string &subInfo)
{ {
int linkType = -1; int linkType = -1;
std::vector<nodeInfo> nodes; std::vector<nodeInfo> nodes;
nodeInfo node; nodeInfo node;
std::string strSub; std::string strSub, extra_headers;
link = replace_all_distinct(link, "\"", ""); link = replace_all_distinct(link, "\"", "");
writeLog(LOG_TYPE_INFO, "Received Link."); writeLog(LOG_TYPE_INFO, "Received Link.");
@@ -52,7 +52,7 @@ int addNodes(std::string link, std::vector<nodeInfo> &allNodes, int groupID, std
writeLog(LOG_TYPE_INFO, "Downloading subscription data..."); writeLog(LOG_TYPE_INFO, "Downloading subscription data...");
if(strFind(link, "surge:///install-config")) //surge config link if(strFind(link, "surge:///install-config")) //surge config link
link = UrlDecode(getUrlArg(link, "url")); link = UrlDecode(getUrlArg(link, "url"));
strSub = webGet(link, proxy); strSub = webGet(link, proxy, extra_headers);
/* /*
if(strSub.size() == 0) if(strSub.size() == 0)
{ {
@@ -70,11 +70,14 @@ int addNodes(std::string link, std::vector<nodeInfo> &allNodes, int groupID, std
if(strSub.size()) if(strSub.size())
{ {
writeLog(LOG_TYPE_INFO, "Parsing subscription data..."); writeLog(LOG_TYPE_INFO, "Parsing subscription data...");
if(explodeConfContent(strSub, override_conf_port, socksport, ss_libev, ssr_libev, nodes, exclude_remarks, include_remarks) == SPEEDTEST_ERROR_UNRECOGFILE) if(explodeConfContent(strSub, override_conf_port, socksport, ss_libev, ssr_libev, nodes) == SPEEDTEST_ERROR_UNRECOGFILE)
{ {
writeLog(LOG_TYPE_ERROR, "Invalid subscription!"); writeLog(LOG_TYPE_ERROR, "Invalid subscription!");
return -1; return -1;
} }
if(!getSubInfoFromHeader(extra_headers, subInfo))
getSubInfoFromNodes(nodes, stream_rules, time_rules, subInfo);
filterNodes(nodes, exclude_remarks, include_remarks, groupID);
for(nodeInfo &x : nodes) for(nodeInfo &x : nodes)
x.groupID = groupID; x.groupID = groupID;
copyNodes(nodes, allNodes); copyNodes(nodes, allNodes);
@@ -89,11 +92,13 @@ int addNodes(std::string link, std::vector<nodeInfo> &allNodes, int groupID, std
if(api_mode) if(api_mode)
return -1; return -1;
writeLog(LOG_TYPE_INFO, "Parsing configuration file data..."); writeLog(LOG_TYPE_INFO, "Parsing configuration file data...");
if(explodeConf(link, override_conf_port, socksport, ss_libev, ssr_libev, nodes, exclude_remarks, include_remarks) == SPEEDTEST_ERROR_UNRECOGFILE) if(explodeConf(link, override_conf_port, socksport, ss_libev, ssr_libev, nodes) == SPEEDTEST_ERROR_UNRECOGFILE)
{ {
writeLog(LOG_TYPE_ERROR, "Invalid configuration file!"); writeLog(LOG_TYPE_ERROR, "Invalid configuration file!");
return -1; return -1;
} }
getSubInfoFromNodes(nodes, stream_rules, time_rules, subInfo);
filterNodes(nodes, exclude_remarks, include_remarks, groupID);
for(nodeInfo &x : nodes) for(nodeInfo &x : nodes)
x.groupID = groupID; x.groupID = groupID;
copyNodes(nodes, allNodes); copyNodes(nodes, allNodes);
+1 -1
View File
@@ -6,6 +6,6 @@
#include "nodeinfo.h" #include "nodeinfo.h"
int addNodes(std::string link, std::vector<nodeInfo> &allNodes, int groupID, std::string proxy, string_array &exclude_remarks, string_array &include_remarks); int addNodes(std::string link, std::vector<nodeInfo> &allNodes, int groupID, std::string proxy, string_array &exclude_remarks, string_array &include_remarks, string_array &stream_rules, string_array &time_rules, std::string &subInfo);
#endif // NODEMANIP_H_INCLUDED #endif // NODEMANIP_H_INCLUDED
+56 -50
View File
@@ -8,57 +8,63 @@
#include "misc.h" #include "misc.h"
#include "nodeinfo.h" #include "nodeinfo.h"
#define SPEEDTEST_ERROR_NONE 0 enum
#define SPEEDTEST_ERROR_UNDEFINED 100 {
#define SPEEDTEST_ERROR_WSAERR 99 SPEEDTEST_ERROR_UNDEFINED = -13,
#define SPEEDTEST_ERROR_SOCKETERR 98 SPEEDTEST_ERROR_WSAERR,
#define SPEEDTEST_ERROR_NORECOGLINK 97 SPEEDTEST_ERROR_SOCKETERR,
#define SPEEDTEST_ERROR_NOCONNECTION 96 SPEEDTEST_ERROR_NORECOGLINK,
#define SPEEDTEST_ERROR_INVALIDSUB 95 SPEEDTEST_ERROR_NOCONNECTION,
#define SPEEDTEST_ERROR_NONODES 94 SPEEDTEST_ERROR_INVALIDSUB,
#define SPEEDTEST_ERROR_NORESOLVE 93 SPEEDTEST_ERROR_NONODES,
#define SPEEDTEST_ERROR_RETEST 92 SPEEDTEST_ERROR_NORESOLVE,
#define SPEEDTEST_ERROR_NOSPEED 91 SPEEDTEST_ERROR_RETEST,
#define SPEEDTEST_ERROR_UNRECOGFILE 90 SPEEDTEST_ERROR_NOSPEED,
#define SPEEDTEST_ERROR_SUBFETCHERR 89 SPEEDTEST_ERROR_UNRECOGFILE,
#define SPEEDTEST_ERROR_GEOIPERR 88 SPEEDTEST_ERROR_SUBFETCHERR,
SPEEDTEST_ERROR_GEOIPERR,
SPEEDTEST_ERROR_NONE
};
#define SPEEDTEST_MESSAGE_WELCOME 0 enum
#define SPEEDTEST_MESSAGE_FOUNDVMESS 1 {
#define SPEEDTEST_MESSAGE_FOUNDSS 2 SPEEDTEST_MESSAGE_WELCOME = 1,
#define SPEEDTEST_MESSAGE_FOUNDSSR 3 SPEEDTEST_MESSAGE_FOUNDVMESS,
#define SPEEDTEST_MESSAGE_FOUNDSUB 4 SPEEDTEST_MESSAGE_FOUNDSS,
#define SPEEDTEST_MESSAGE_GOTSERVER 5 SPEEDTEST_MESSAGE_FOUNDSSR,
#define SPEEDTEST_MESSAGE_STARTPING 6 SPEEDTEST_MESSAGE_FOUNDSUB,
#define SPEEDTEST_MESSAGE_GOTPING 7 SPEEDTEST_MESSAGE_GOTSERVER,
#define SPEEDTEST_MESSAGE_STARTSPEED 8 SPEEDTEST_MESSAGE_STARTPING,
#define SPEEDTEST_MESSAGE_GOTSPEED 9 SPEEDTEST_MESSAGE_GOTPING,
#define SPEEDTEST_MESSAGE_GOTRESULT 10 SPEEDTEST_MESSAGE_STARTSPEED,
#define SPEEDTEST_MESSAGE_TRAFFIC 11 SPEEDTEST_MESSAGE_GOTSPEED,
#define SPEEDTEST_MESSAGE_PICSAVING 12 SPEEDTEST_MESSAGE_GOTRESULT,
#define SPEEDTEST_MESSAGE_PICSAVED 13 SPEEDTEST_MESSAGE_TRAFFIC,
#define SPEEDTEST_MESSAGE_GROUP 14 SPEEDTEST_MESSAGE_PICSAVING,
#define SPEEDTEST_MESSAGE_FETCHSUB 15 SPEEDTEST_MESSAGE_PICSAVED,
#define SPEEDTEST_MESSAGE_BEGIN 16 SPEEDTEST_MESSAGE_GROUP,
#define SPEEDTEST_MESSAGE_FOUNDLOCAL 17 SPEEDTEST_MESSAGE_FETCHSUB,
#define SPEEDTEST_MESSAGE_PARSING 18 SPEEDTEST_MESSAGE_BEGIN,
#define SPEEDTEST_MESSAGE_FOUNDUPD 19 SPEEDTEST_MESSAGE_FOUNDLOCAL,
#define SPEEDTEST_MESSAGE_PICDATA 20 SPEEDTEST_MESSAGE_PARSING,
#define SPEEDTEST_MESSAGE_STARTGPING 21 SPEEDTEST_MESSAGE_FOUNDUPD,
#define SPEEDTEST_MESSAGE_GOTGPING 22 SPEEDTEST_MESSAGE_PICDATA,
#define SPEEDTEST_MESSAGE_FOUNDSOCKS 23 SPEEDTEST_MESSAGE_STARTGPING,
#define SPEEDTEST_MESSAGE_STARTGEOIP 24 SPEEDTEST_MESSAGE_GOTGPING,
#define SPEEDTEST_MESSAGE_GOTGEOIP 25 SPEEDTEST_MESSAGE_FOUNDSOCKS,
#define SPEEDTEST_MESSAGE_FOUNDSSCONF 26 SPEEDTEST_MESSAGE_STARTGEOIP,
#define SPEEDTEST_MESSAGE_MULTILINK 27 SPEEDTEST_MESSAGE_GOTGEOIP,
#define SPEEDTEST_MESSAGE_PICSAVINGMULTI 28 SPEEDTEST_MESSAGE_FOUNDSSCONF,
#define SPEEDTEST_MESSAGE_PICSAVEDMULTI 29 SPEEDTEST_MESSAGE_MULTILINK,
#define SPEEDTEST_MESSAGE_STARTUPD 30 SPEEDTEST_MESSAGE_PICSAVINGMULTI,
#define SPEEDTEST_MESSAGE_GOTUPD 31 SPEEDTEST_MESSAGE_PICSAVEDMULTI,
#define SPEEDTEST_MESSAGE_FOUNDSSTAP 32 SPEEDTEST_MESSAGE_STARTUPD,
#define SPEEDTEST_MESSAGE_FOUNDNETCH 33 SPEEDTEST_MESSAGE_GOTUPD,
#define SPEEDTEST_MESSAGE_FOUNDHTTP 34 SPEEDTEST_MESSAGE_FOUNDSSTAP,
#define SPEEDTEST_MESSAGE_EOF 49 SPEEDTEST_MESSAGE_FOUNDNETCH,
SPEEDTEST_MESSAGE_FOUNDHTTP,
SPEEDTEST_MESSAGE_EOF
};
#define SS_DEFAULT_GROUP "SSProvider" #define SS_DEFAULT_GROUP "SSProvider"
#define SSR_DEFAULT_GROUP "SSRProvider" #define SSR_DEFAULT_GROUP "SSRProvider"
+172 -25
View File
@@ -1,7 +1,10 @@
#include <fstream> #include <fstream>
#include <algorithm> #include <algorithm>
#include <time.h>
#include <rapidjson/document.h> #include <rapidjson/document.h>
#include <pcrecpp.h>
#include "misc.h" #include "misc.h"
#include "printout.h" #include "printout.h"
@@ -997,6 +1000,7 @@ bool explodeSurge(std::string surge, std::string custom_port, int local_port, st
*/ */
ini.store_isolated_line = true; ini.store_isolated_line = true;
ini.keep_empty_section = false;
ini.SetIsolatedItemsSection("Proxy"); ini.SetIsolatedItemsSection("Proxy");
ini.IncludeSection("Proxy"); ini.IncludeSection("Proxy");
ini.Parse(surge); ini.Parse(surge);
@@ -1388,7 +1392,7 @@ bool chkIgnore(const nodeInfo &node, string_array &exclude_remarks, string_array
return excluded || !included; return excluded || !included;
} }
int explodeConf(std::string filepath, std::string custom_port, int local_port, bool sslibev, bool ssrlibev, std::vector<nodeInfo> &nodes, string_array &exclude_remarks, string_array &include_remarks) int explodeConf(std::string filepath, std::string custom_port, int local_port, bool sslibev, bool ssrlibev, std::vector<nodeInfo> &nodes)
{ {
std::ifstream infile; std::ifstream infile;
std::stringstream contentstrm; std::stringstream contentstrm;
@@ -1397,12 +1401,11 @@ int explodeConf(std::string filepath, std::string custom_port, int local_port, b
contentstrm << infile.rdbuf(); contentstrm << infile.rdbuf();
infile.close(); infile.close();
return explodeConfContent(contentstrm.str(), custom_port, local_port, sslibev, ssrlibev, nodes, exclude_remarks, include_remarks); return explodeConfContent(contentstrm.str(), custom_port, local_port, sslibev, ssrlibev, nodes);
} }
int explodeConfContent(std::string content, std::string custom_port, int local_port, bool sslibev, bool ssrlibev, std::vector<nodeInfo> &nodes, string_array &exclude_remarks, string_array &include_remarks) int explodeConfContent(std::string content, std::string custom_port, int local_port, bool sslibev, bool ssrlibev, std::vector<nodeInfo> &nodes)
{ {
unsigned int index = 0;
int filetype = -1; int filetype = -1;
std::vector<nodeInfo>::iterator iter; std::vector<nodeInfo>::iterator iter;
@@ -1443,32 +1446,13 @@ int explodeConfContent(std::string content, std::string custom_port, int local_p
break; break;
default: default:
//try to parse as a local subscription //try to parse as a local subscription
explodeSub(content, sslibev, ssrlibev, custom_port, local_port, nodes, exclude_remarks, include_remarks); explodeSub(content, sslibev, ssrlibev, custom_port, local_port, nodes);
} }
if(nodes.size() == 0) if(nodes.size() == 0)
return SPEEDTEST_ERROR_UNRECOGFILE; return SPEEDTEST_ERROR_UNRECOGFILE;
else else
return SPEEDTEST_ERROR_NONE; return SPEEDTEST_ERROR_NONE;
iter = nodes.begin();
while(iter != nodes.end())
{
if(chkIgnore(*iter, exclude_remarks, include_remarks))
{
writeLog(LOG_TYPE_INFO, "Node " + iter->group + " - " + iter->remarks + " has been ignored and will not be added.");
nodes.erase(iter);
}
else
{
writeLog(LOG_TYPE_INFO, "Node " + iter->group + " - " + iter->remarks + " has been added.");
iter->id = index;
++index;
++iter;
}
}
return SPEEDTEST_ERROR_NONE;
} }
void explode(std::string link, bool sslibev, bool ssrlibev, std::string custom_port, int local_port, nodeInfo &node) void explode(std::string link, bool sslibev, bool ssrlibev, std::string custom_port, int local_port, nodeInfo &node)
@@ -1485,7 +1469,7 @@ void explode(std::string link, bool sslibev, bool ssrlibev, std::string custom_p
explodeNetch(link, sslibev, ssrlibev, custom_port, local_port, node); explodeNetch(link, sslibev, ssrlibev, custom_port, local_port, node);
} }
void explodeSub(std::string sub, bool sslibev, bool ssrlibev, std::string custom_port, int local_port, std::vector<nodeInfo> &nodes, string_array &exclude_remarks, string_array &include_remarks) void explodeSub(std::string sub, bool sslibev, bool ssrlibev, std::string custom_port, int local_port, std::vector<nodeInfo> &nodes)
{ {
std::stringstream strstream; std::stringstream strstream;
std::string strLink; std::string strLink;
@@ -1540,7 +1524,10 @@ void explodeSub(std::string sub, bool sslibev, bool ssrlibev, std::string custom
nodes.push_back(node); nodes.push_back(node);
} }
} }
}
void filterNodes(std::vector<nodeInfo> &nodes, string_array &exclude_remarks, string_array &include_remarks, int groupID)
{
int index = 0; int index = 0;
std::vector<nodeInfo>::iterator iter = nodes.begin(); std::vector<nodeInfo>::iterator iter = nodes.begin();
while(iter != nodes.end()) while(iter != nodes.end())
@@ -1554,8 +1541,168 @@ void explodeSub(std::string sub, bool sslibev, bool ssrlibev, std::string custom
{ {
writeLog(LOG_TYPE_INFO, "Node " + iter->group + " - " + iter->remarks + " has been added."); writeLog(LOG_TYPE_INFO, "Node " + iter->group + " - " + iter->remarks + " has been added.");
iter->id = index; iter->id = index;
iter->groupID = groupID;
++index; ++index;
++iter; ++iter;
} }
} }
} }
static inline unsigned long long streamToInt(std::string stream)
{
if(!stream.size())
return 0;
double streamval = 1.0;
if(stream.find("GB") != std::string::npos)
streamval = std::pow(1024, 3) * stof(stream.substr(0, stream.size() - 2));
else if(stream.find("TB") != std::string::npos)
streamval = std::pow(1024, 4) * stof(stream.substr(0, stream.size() - 2));
else if(stream.find("PB") != std::string::npos)
streamval = std::pow(1024, 5) * stof(stream.substr(0, stream.size() - 2));
else if(stream.find("MB") != std::string::npos)
streamval = std::pow(1024, 2) * stof(stream.substr(0, stream.size() - 2));
else if(stream.find("KB") != std::string::npos)
streamval = 1024.0 * stof(stream.substr(0, stream.size() - 2));
else if(stream.find("B") != std::string::npos)
streamval = 1.0 * stof(stream.substr(0, stream.size() - 1));
return (unsigned long long)streamval;
}
static inline double percentToDouble(std::string percent)
{
return stof(percent.erase(percent.size() - 1)) / 100.0;
}
time_t dateStringToTimestamp(std::string date)
{
std::vector<std::string> date_array = split(date, ":");
if(date_array.size() != 6)
return 0;
time_t rawtime;
struct tm *expire_time;
time(&rawtime);
expire_time = localtime(&rawtime);
expire_time->tm_year = to_int(date_array[0], 1900) - 1900;
expire_time->tm_mon = to_int(date_array[1], 1) - 1;
expire_time->tm_mday = to_int(date_array[2]);
expire_time->tm_hour = to_int(date_array[3]);
expire_time->tm_min = to_int(date_array[4]);
expire_time->tm_sec = to_int(date_array[5]);
return mktime(expire_time);
}
bool getSubInfoFromHeader(std::string &header, std::string &result)
{
bool ret = false;
pcrecpp::RE reg("^(?i:Subscription-UserInfo): (.*?)\\r$", pcrecpp::MULTILINE());
try
{
ret = reg.PartialMatch(header, &result);
}
catch (std::exception &e)
{
//ignore
}
return ret;
}
bool getSubInfoFromNodes(std::vector<nodeInfo> &nodes, string_array &stream_rules, string_array &time_rules, std::string &result)
{
std::string remarks, pattern, target, stream_info, time_info;
string_array vArray;
for(nodeInfo &x : nodes)
{
remarks = x.remarks;
if(!stream_info.size())
{
for(std::string &y : stream_rules)
{
vArray = split(y, "|");
if(vArray.size() != 2)
continue;
pattern = vArray[0];
target = vArray[1];
pcrecpp::RE reg(pattern, pcrecpp::UTF8());
if(reg.FullMatch(remarks))
{
if(target.find("$") != target.npos)
target = replace_all_distinct(target, "$", "\\");
if(reg.GlobalReplace(target, &remarks))
stream_info = remarks;
}
else
continue;
}
}
remarks = x.remarks;
if(!time_info.size())
{
for(std::string &y : time_rules)
{
vArray = split(y, "|");
if(vArray.size() != 2)
continue;
pattern = vArray[0];
target = vArray[1];
pcrecpp::RE reg(pattern, pcrecpp::UTF8());
if(reg.FullMatch(remarks))
{
if(target.find("$") != target.npos)
target = replace_all_distinct(target, "$", "\\");
if(reg.GlobalReplace(target, &remarks))
time_info = remarks;
}
else
continue;
}
}
if(stream_info.size() && time_info.size())
break;
}
if(!stream_info.size() && !time_info.size())
return false;
//calculate how much stream left
unsigned long long total = 0, left = 0, used = 0, expire = 0;
std::string total_str = getUrlArg(stream_info, "total"), left_str = getUrlArg(stream_info, "left"), used_str = getUrlArg(stream_info, "used");
if(strFind(total_str, "%"))
{
if(used_str.size())
{
used = streamToInt(used_str);
total = used / (1 - percentToDouble(total_str));
}
else if(left_str.size())
{
left = streamToInt(left_str);
total = left / percentToDouble(total_str);
used = total - left;
}
}
else
{
total = streamToInt(total_str);
if(used_str.size())
{
used = streamToInt(used_str);
}
else if(left_str.size())
{
left = streamToInt(left_str);
used = total - left;
}
}
result = "upload=0; download=" + std::to_string(used) + "; total=" + std::to_string(total) + ";";
//calculate expire time
expire = dateStringToTimestamp(time_info);
if(expire != 0)
result += " expire=" + std::to_string(expire) + ";";
return true;
}
+6 -3
View File
@@ -20,9 +20,12 @@ void explodeShadowrocket(std::string kit, std::string custom_port, int local_por
void explodeKitsunebi(std::string kit, std::string custom_port, int local_port, nodeInfo &node); void explodeKitsunebi(std::string kit, std::string custom_port, int local_port, nodeInfo &node);
void explode(std::string link, bool sslibev, bool ssrlibev, std::string custom_port, int local_port, nodeInfo &node); void explode(std::string link, bool sslibev, bool ssrlibev, std::string custom_port, int local_port, nodeInfo &node);
void explodeSSD(std::string link, bool libev, std::string custom_port, int local_port, std::vector<nodeInfo> &nodes); void explodeSSD(std::string link, bool libev, std::string custom_port, int local_port, std::vector<nodeInfo> &nodes);
void explodeSub(std::string sub, bool sslibev, bool ssrlibev, std::string custom_port, int local_port, std::vector<nodeInfo> &nodes, string_array &exclude_remarks, string_array &include_remarks); void explodeSub(std::string sub, bool sslibev, bool ssrlibev, std::string custom_port, int local_port, std::vector<nodeInfo> &nodes);
int explodeConf(std::string filepath, std::string custom_port, int local_port, bool sslibev, bool ssrlibev, std::vector<nodeInfo> &nodes, string_array &exclude_remarks, string_array &include_remarks); int explodeConf(std::string filepath, std::string custom_port, int local_port, bool sslibev, bool ssrlibev, std::vector<nodeInfo> &nodes);
int explodeConfContent(std::string content, std::string custom_port, int local_port, bool sslibev, bool ssrlibev, std::vector<nodeInfo> &nodes, string_array &exclude_remarks, string_array &include_remarks); int explodeConfContent(std::string content, std::string custom_port, int local_port, bool sslibev, bool ssrlibev, std::vector<nodeInfo> &nodes);
bool chkIgnore(const nodeInfo &node, string_array &exclude_remarks, string_array &include_remarks); bool chkIgnore(const nodeInfo &node, string_array &exclude_remarks, string_array &include_remarks);
void filterNodes(std::vector<nodeInfo> &nodes, string_array &exclude_remarks, string_array &include_remarks, int groupID);
bool getSubInfoFromHeader(std::string &header, std::string &result);
bool getSubInfoFromNodes(std::vector<nodeInfo> &nodes, string_array &stream_rules, string_array &time_rules, std::string &result);
#endif // SPEEDTESTUTIL_H_INCLUDED #endif // SPEEDTESTUTIL_H_INCLUDED