mirror of
https://github.com/asdlokj1qpi233/subconverter.git
synced 2025-10-27 20:03:01 +00:00
Enhancements
Add Subscription-UserInfo header to exporter, supports extracting from original headers and from info nodes. Optimize codes.
This commit is contained in:
@@ -35,6 +35,21 @@ proxy_subscription=NONE
|
||||
;Append a proxy type string ([SS] [SSR] [VMess]) to node remark.
|
||||
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]
|
||||
udp_flag=false
|
||||
tcp_fast_open_flag=false
|
||||
|
||||
@@ -9,12 +9,15 @@
|
||||
|
||||
#include "misc.h"
|
||||
|
||||
#define INIREADER_EXCEPTION_NONE 0
|
||||
#define INIREADER_EXCEPTION_EMPTY -1
|
||||
#define INIREADER_EXCEPTION_DUPLICATE -2
|
||||
#define INIREADER_EXCEPTION_OUTOFBOUND -3
|
||||
#define INIREADER_EXCEPTION_NOTEXIST -4
|
||||
#define INIREADER_EXCEPTION_NOTPARSED -5
|
||||
enum
|
||||
{
|
||||
INIREADER_EXCEPTION_EMPTY = -5,
|
||||
INIREADER_EXCEPTION_DUPLICATE,
|
||||
INIREADER_EXCEPTION_OUTOFBOUND,
|
||||
INIREADER_EXCEPTION_NOTEXIST,
|
||||
INIREADER_EXCEPTION_NOTPARSED,
|
||||
INIREADER_EXCEPTION_NONE
|
||||
};
|
||||
|
||||
#define __SAVE_ERROR_AND_RETURN(x) {last_error = x; return last_error;}
|
||||
|
||||
@@ -80,6 +83,11 @@ public:
|
||||
*/
|
||||
bool allow_dup_section_titles = false;
|
||||
|
||||
/**
|
||||
* @brief Keep an empty section while parsing
|
||||
*/
|
||||
bool keep_empty_section = true;
|
||||
|
||||
/**
|
||||
* @brief Initialize the reader.
|
||||
*/
|
||||
@@ -224,23 +232,24 @@ public:
|
||||
thisSection = strLine.substr(1, lineSize - 2); //save section title
|
||||
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(allow_dup_section_titles)
|
||||
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
|
||||
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
|
||||
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
|
||||
read_sections.push_back(curSection); //add to read sections list
|
||||
if(std::count(section_order.cbegin(), section_order.cend(), curSection) == 0)
|
||||
section_order.emplace_back(curSection);
|
||||
}
|
||||
@@ -255,7 +264,7 @@ public:
|
||||
if(include_sections.size() && include_sections == read_sections) //all included sections has been read
|
||||
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
|
||||
{
|
||||
@@ -265,13 +274,14 @@ public:
|
||||
existItemGroup = ini_content.at(curSection); //get the old items
|
||||
for(auto &x : existItemGroup)
|
||||
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
|
||||
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
|
||||
read_sections.emplace_back(curSection); //add to read sections list
|
||||
if(std::count(section_order.cbegin(), section_order.cend(), curSection) == 0)
|
||||
section_order.emplace_back(curSection);
|
||||
}
|
||||
@@ -803,7 +813,7 @@ public:
|
||||
content += "\n";
|
||||
}
|
||||
|
||||
return content.substr(0, content.size() - 2);
|
||||
return content.erase(content.size() - 2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
59
src/main.cpp
59
src/main.cpp
@@ -20,7 +20,7 @@
|
||||
//common settings
|
||||
std::string pref_path = "pref.ini";
|
||||
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::string listen_address = "127.0.0.1", default_url, managed_config_prefix;
|
||||
int listen_port = 25500, max_pending_connections = 10, max_concurrent_threads = 4;
|
||||
@@ -151,7 +151,7 @@ void readConf()
|
||||
eraseElements(def_include_remarks);
|
||||
eraseElements(clash_extra_group);
|
||||
eraseElements(rulesets);
|
||||
string_array emojis_temp, renames_temp;
|
||||
string_array tempArray;
|
||||
|
||||
ini.EnterSection("common");
|
||||
if(ini.ItemExist("api_mode"))
|
||||
@@ -201,8 +201,26 @@ void readConf()
|
||||
filter_deprecated = ini.GetBool("filter_deprecated_nodes");
|
||||
if(ini.ItemPrefixExist("rename_node"))
|
||||
{
|
||||
ini.GetAll("rename_node", renames_temp);
|
||||
safe_set_renames(renames_temp);
|
||||
ini.GetAll("rename_node", tempArray);
|
||||
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");
|
||||
if(ini.ItemPrefixExist("rule"))
|
||||
{
|
||||
ini.GetAll("rule", emojis_temp);
|
||||
safe_set_emojis(emojis_temp);
|
||||
ini.GetAll("rule", tempArray);
|
||||
safe_set_emojis(tempArray);
|
||||
eraseElements(tempArray);
|
||||
}
|
||||
|
||||
ini.EnterSection("ruleset");
|
||||
@@ -284,6 +303,7 @@ int loadExternalConfig(std::string &path, ExternalConfig &ext, std::string proxy
|
||||
|
||||
INIReader ini;
|
||||
ini.store_isolated_line = true;
|
||||
ini.keep_empty_section = false;
|
||||
ini.SetIsolatedItemsSection("custom");
|
||||
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::vector<ruleset_content> rca;
|
||||
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())
|
||||
return "Invalid request!";
|
||||
@@ -512,11 +533,12 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
custom_group = group;
|
||||
|
||||
//start parsing urls
|
||||
string_array stream_temp = safe_get_streams(), time_temp = safe_get_times();
|
||||
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) == -1)
|
||||
if(addNodes(x, nodes, groupID, proxy, exclude_remarks, include_remarks, stream_temp, time_temp, subInfo) == -1)
|
||||
{
|
||||
*status_code = 400;
|
||||
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!";
|
||||
}
|
||||
|
||||
if(subInfo.size() && groupID == 1)
|
||||
extra_headers.emplace("Subscription-UserInfo", subInfo);
|
||||
|
||||
std::cerr<<"Generate target: ";
|
||||
if(target == "clash" || target == "clashr")
|
||||
{
|
||||
@@ -672,6 +697,7 @@ std::string simpleToClashR(RESPONSE_CALLBACK_ARGS)
|
||||
std::vector<nodeInfo> nodes;
|
||||
string_array extra_group, extra_ruleset, include_remarks, exclude_remarks;
|
||||
std::vector<ruleset_content> rca;
|
||||
std::string subInfo;
|
||||
|
||||
if(!url.size())
|
||||
url = default_url;
|
||||
@@ -707,9 +733,22 @@ std::string simpleToClashR(RESPONSE_CALLBACK_ARGS)
|
||||
include_remarks = def_include_remarks;
|
||||
exclude_remarks = def_exclude_remarks;
|
||||
|
||||
std::cerr<<"Fetching node data from url '"<<url<<"'.\n";
|
||||
addNodes(url, nodes, 0, proxy, exclude_remarks, include_remarks);
|
||||
|
||||
//start parsing urls
|
||||
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())
|
||||
{
|
||||
*status_code = 400;
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
|
||||
//safety lock for multi-thread
|
||||
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 stream_rules, time_rules;
|
||||
|
||||
string_array safe_get_emojis()
|
||||
{
|
||||
@@ -20,6 +21,18 @@ string_array safe_get_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)
|
||||
{
|
||||
guarded_mutex guard(on_emoji);
|
||||
@@ -31,3 +44,15 @@ void safe_set_renames(string_array &data)
|
||||
guarded_mutex guard(on_rename);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
|
||||
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_renames();
|
||||
string_array safe_get_streams();
|
||||
string_array safe_get_times();
|
||||
void safe_set_emojis(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
|
||||
|
||||
@@ -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;
|
||||
std::vector<nodeInfo> nodes;
|
||||
nodeInfo node;
|
||||
std::string strSub;
|
||||
std::string strSub, extra_headers;
|
||||
|
||||
link = replace_all_distinct(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...");
|
||||
if(strFind(link, "surge:///install-config")) //surge config link
|
||||
link = UrlDecode(getUrlArg(link, "url"));
|
||||
strSub = webGet(link, proxy);
|
||||
strSub = webGet(link, proxy, extra_headers);
|
||||
/*
|
||||
if(strSub.size() == 0)
|
||||
{
|
||||
@@ -70,11 +70,14 @@ int addNodes(std::string link, std::vector<nodeInfo> &allNodes, int groupID, std
|
||||
if(strSub.size())
|
||||
{
|
||||
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!");
|
||||
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)
|
||||
x.groupID = groupID;
|
||||
copyNodes(nodes, allNodes);
|
||||
@@ -89,11 +92,13 @@ int addNodes(std::string link, std::vector<nodeInfo> &allNodes, int groupID, std
|
||||
if(api_mode)
|
||||
return -1;
|
||||
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!");
|
||||
return -1;
|
||||
}
|
||||
getSubInfoFromNodes(nodes, stream_rules, time_rules, subInfo);
|
||||
filterNodes(nodes, exclude_remarks, include_remarks, groupID);
|
||||
for(nodeInfo &x : nodes)
|
||||
x.groupID = groupID;
|
||||
copyNodes(nodes, allNodes);
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
|
||||
#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
|
||||
|
||||
106
src/printout.h
106
src/printout.h
@@ -8,57 +8,63 @@
|
||||
#include "misc.h"
|
||||
#include "nodeinfo.h"
|
||||
|
||||
#define SPEEDTEST_ERROR_NONE 0
|
||||
#define SPEEDTEST_ERROR_UNDEFINED 100
|
||||
#define SPEEDTEST_ERROR_WSAERR 99
|
||||
#define SPEEDTEST_ERROR_SOCKETERR 98
|
||||
#define SPEEDTEST_ERROR_NORECOGLINK 97
|
||||
#define SPEEDTEST_ERROR_NOCONNECTION 96
|
||||
#define SPEEDTEST_ERROR_INVALIDSUB 95
|
||||
#define SPEEDTEST_ERROR_NONODES 94
|
||||
#define SPEEDTEST_ERROR_NORESOLVE 93
|
||||
#define SPEEDTEST_ERROR_RETEST 92
|
||||
#define SPEEDTEST_ERROR_NOSPEED 91
|
||||
#define SPEEDTEST_ERROR_UNRECOGFILE 90
|
||||
#define SPEEDTEST_ERROR_SUBFETCHERR 89
|
||||
#define SPEEDTEST_ERROR_GEOIPERR 88
|
||||
enum
|
||||
{
|
||||
SPEEDTEST_ERROR_UNDEFINED = -13,
|
||||
SPEEDTEST_ERROR_WSAERR,
|
||||
SPEEDTEST_ERROR_SOCKETERR,
|
||||
SPEEDTEST_ERROR_NORECOGLINK,
|
||||
SPEEDTEST_ERROR_NOCONNECTION,
|
||||
SPEEDTEST_ERROR_INVALIDSUB,
|
||||
SPEEDTEST_ERROR_NONODES,
|
||||
SPEEDTEST_ERROR_NORESOLVE,
|
||||
SPEEDTEST_ERROR_RETEST,
|
||||
SPEEDTEST_ERROR_NOSPEED,
|
||||
SPEEDTEST_ERROR_UNRECOGFILE,
|
||||
SPEEDTEST_ERROR_SUBFETCHERR,
|
||||
SPEEDTEST_ERROR_GEOIPERR,
|
||||
SPEEDTEST_ERROR_NONE
|
||||
};
|
||||
|
||||
#define SPEEDTEST_MESSAGE_WELCOME 0
|
||||
#define SPEEDTEST_MESSAGE_FOUNDVMESS 1
|
||||
#define SPEEDTEST_MESSAGE_FOUNDSS 2
|
||||
#define SPEEDTEST_MESSAGE_FOUNDSSR 3
|
||||
#define SPEEDTEST_MESSAGE_FOUNDSUB 4
|
||||
#define SPEEDTEST_MESSAGE_GOTSERVER 5
|
||||
#define SPEEDTEST_MESSAGE_STARTPING 6
|
||||
#define SPEEDTEST_MESSAGE_GOTPING 7
|
||||
#define SPEEDTEST_MESSAGE_STARTSPEED 8
|
||||
#define SPEEDTEST_MESSAGE_GOTSPEED 9
|
||||
#define SPEEDTEST_MESSAGE_GOTRESULT 10
|
||||
#define SPEEDTEST_MESSAGE_TRAFFIC 11
|
||||
#define SPEEDTEST_MESSAGE_PICSAVING 12
|
||||
#define SPEEDTEST_MESSAGE_PICSAVED 13
|
||||
#define SPEEDTEST_MESSAGE_GROUP 14
|
||||
#define SPEEDTEST_MESSAGE_FETCHSUB 15
|
||||
#define SPEEDTEST_MESSAGE_BEGIN 16
|
||||
#define SPEEDTEST_MESSAGE_FOUNDLOCAL 17
|
||||
#define SPEEDTEST_MESSAGE_PARSING 18
|
||||
#define SPEEDTEST_MESSAGE_FOUNDUPD 19
|
||||
#define SPEEDTEST_MESSAGE_PICDATA 20
|
||||
#define SPEEDTEST_MESSAGE_STARTGPING 21
|
||||
#define SPEEDTEST_MESSAGE_GOTGPING 22
|
||||
#define SPEEDTEST_MESSAGE_FOUNDSOCKS 23
|
||||
#define SPEEDTEST_MESSAGE_STARTGEOIP 24
|
||||
#define SPEEDTEST_MESSAGE_GOTGEOIP 25
|
||||
#define SPEEDTEST_MESSAGE_FOUNDSSCONF 26
|
||||
#define SPEEDTEST_MESSAGE_MULTILINK 27
|
||||
#define SPEEDTEST_MESSAGE_PICSAVINGMULTI 28
|
||||
#define SPEEDTEST_MESSAGE_PICSAVEDMULTI 29
|
||||
#define SPEEDTEST_MESSAGE_STARTUPD 30
|
||||
#define SPEEDTEST_MESSAGE_GOTUPD 31
|
||||
#define SPEEDTEST_MESSAGE_FOUNDSSTAP 32
|
||||
#define SPEEDTEST_MESSAGE_FOUNDNETCH 33
|
||||
#define SPEEDTEST_MESSAGE_FOUNDHTTP 34
|
||||
#define SPEEDTEST_MESSAGE_EOF 49
|
||||
enum
|
||||
{
|
||||
SPEEDTEST_MESSAGE_WELCOME = 1,
|
||||
SPEEDTEST_MESSAGE_FOUNDVMESS,
|
||||
SPEEDTEST_MESSAGE_FOUNDSS,
|
||||
SPEEDTEST_MESSAGE_FOUNDSSR,
|
||||
SPEEDTEST_MESSAGE_FOUNDSUB,
|
||||
SPEEDTEST_MESSAGE_GOTSERVER,
|
||||
SPEEDTEST_MESSAGE_STARTPING,
|
||||
SPEEDTEST_MESSAGE_GOTPING,
|
||||
SPEEDTEST_MESSAGE_STARTSPEED,
|
||||
SPEEDTEST_MESSAGE_GOTSPEED,
|
||||
SPEEDTEST_MESSAGE_GOTRESULT,
|
||||
SPEEDTEST_MESSAGE_TRAFFIC,
|
||||
SPEEDTEST_MESSAGE_PICSAVING,
|
||||
SPEEDTEST_MESSAGE_PICSAVED,
|
||||
SPEEDTEST_MESSAGE_GROUP,
|
||||
SPEEDTEST_MESSAGE_FETCHSUB,
|
||||
SPEEDTEST_MESSAGE_BEGIN,
|
||||
SPEEDTEST_MESSAGE_FOUNDLOCAL,
|
||||
SPEEDTEST_MESSAGE_PARSING,
|
||||
SPEEDTEST_MESSAGE_FOUNDUPD,
|
||||
SPEEDTEST_MESSAGE_PICDATA,
|
||||
SPEEDTEST_MESSAGE_STARTGPING,
|
||||
SPEEDTEST_MESSAGE_GOTGPING,
|
||||
SPEEDTEST_MESSAGE_FOUNDSOCKS,
|
||||
SPEEDTEST_MESSAGE_STARTGEOIP,
|
||||
SPEEDTEST_MESSAGE_GOTGEOIP,
|
||||
SPEEDTEST_MESSAGE_FOUNDSSCONF,
|
||||
SPEEDTEST_MESSAGE_MULTILINK,
|
||||
SPEEDTEST_MESSAGE_PICSAVINGMULTI,
|
||||
SPEEDTEST_MESSAGE_PICSAVEDMULTI,
|
||||
SPEEDTEST_MESSAGE_STARTUPD,
|
||||
SPEEDTEST_MESSAGE_GOTUPD,
|
||||
SPEEDTEST_MESSAGE_FOUNDSSTAP,
|
||||
SPEEDTEST_MESSAGE_FOUNDNETCH,
|
||||
SPEEDTEST_MESSAGE_FOUNDHTTP,
|
||||
SPEEDTEST_MESSAGE_EOF
|
||||
};
|
||||
|
||||
#define SS_DEFAULT_GROUP "SSProvider"
|
||||
#define SSR_DEFAULT_GROUP "SSRProvider"
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
#include <pcrecpp.h>
|
||||
|
||||
#include "misc.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.keep_empty_section = false;
|
||||
ini.SetIsolatedItemsSection("Proxy");
|
||||
ini.IncludeSection("Proxy");
|
||||
ini.Parse(surge);
|
||||
@@ -1388,7 +1392,7 @@ bool chkIgnore(const nodeInfo &node, string_array &exclude_remarks, string_array
|
||||
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::stringstream contentstrm;
|
||||
@@ -1397,12 +1401,11 @@ int explodeConf(std::string filepath, std::string custom_port, int local_port, b
|
||||
contentstrm << infile.rdbuf();
|
||||
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;
|
||||
std::vector<nodeInfo>::iterator iter;
|
||||
|
||||
@@ -1443,32 +1446,13 @@ int explodeConfContent(std::string content, std::string custom_port, int local_p
|
||||
break;
|
||||
default:
|
||||
//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)
|
||||
return SPEEDTEST_ERROR_UNRECOGFILE;
|
||||
else
|
||||
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)
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
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::string strLink;
|
||||
@@ -1540,7 +1524,10 @@ void explodeSub(std::string sub, bool sslibev, bool ssrlibev, std::string custom
|
||||
nodes.push_back(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void filterNodes(std::vector<nodeInfo> &nodes, string_array &exclude_remarks, string_array &include_remarks, int groupID)
|
||||
{
|
||||
int index = 0;
|
||||
std::vector<nodeInfo>::iterator iter = nodes.begin();
|
||||
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.");
|
||||
iter->id = index;
|
||||
iter->groupID = groupID;
|
||||
++index;
|
||||
++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;
|
||||
}
|
||||
|
||||
@@ -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 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 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);
|
||||
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 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);
|
||||
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);
|
||||
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);
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user