mirror of
https://github.com/asdlokj1qpi233/subconverter.git
synced 2026-11-04 02:34:06 +00:00
Optimizations
Fix stream/time node matcher not working with YAML configuration. Add PCRE2 JIT optimization for filtering nodes. Add space after adding proxy type to node remarks. Add displaying Subscription User Info when generating artifacts in generator mode. Add support for another type of time node. Optimize codes.
This commit is contained in:
6 files changed
+186
-14
No files matched your search
@@ -22,10 +22,12 @@ userinfo:
|
||||
- {match: "^剩余流量:(.*?) (.*)$", replace: "total=$1&left=$2"}
|
||||
- {match: "^Bandwidth: (.*?)/(.*)$", replace: "used=$1&total=$2"}
|
||||
- {match: "^.*剩余(.*?)(?:\\s*?)@(?:.*)$", replace: "total=$1"}
|
||||
- {match: "^.*?流量:(.*?) 剩:(?:.*)$", replace: "total=$1"}
|
||||
time_rule:
|
||||
- {match: "^过期时间:(\\d+)-(\\d+)-(\\d+) (\\d+):(\\d+):(\\d+)$", replace: "$1:$2:$3:$4:$5:$6"}
|
||||
- {match: "^到期时间:(\\d+)-(\\d+)-(\\d+)$", replace: "$1:$2:$3:0:0:0"}
|
||||
- {match: "^Smart Access expire: (\\d+)/(\\d+)/(\\d+)$", replace: "$1:$2:$3:0:0:0"}
|
||||
- {match: "^.*?流量:(?:.*?) 剩:(.*?)天$", replace: "left=$1d"}
|
||||
|
||||
node_pref:
|
||||
udp_flag: false
|
||||
|
||||
@@ -63,6 +63,7 @@ stream_rule=^.*?流量:(.*?) 剩:(?:.*)$|total=$1
|
||||
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
|
||||
time_rule=^.*?流量:(?:.*?) 剩:(.*)$|left=$1d
|
||||
|
||||
[node_pref]
|
||||
udp_flag=false
|
||||
|
||||
+75
-5
@@ -418,13 +418,13 @@ void readYAMLConf(YAML::Node &node)
|
||||
section = node["userinfo"];
|
||||
if(section["stream_rule"].IsSequence())
|
||||
{
|
||||
readRegexMatch(section["stream_rule"], "@", tempArray);
|
||||
readRegexMatch(section["stream_rule"], "|", tempArray);
|
||||
safe_set_streams(tempArray);
|
||||
eraseElements(tempArray);
|
||||
}
|
||||
if(section["time_rule"].IsSequence())
|
||||
{
|
||||
readRegexMatch(section["time_rule"], "@", tempArray);
|
||||
readRegexMatch(section["time_rule"], "|", tempArray);
|
||||
safe_set_times(tempArray);
|
||||
eraseElements(tempArray);
|
||||
}
|
||||
@@ -1697,6 +1697,67 @@ std::string getRewriteRemote(RESPONSE_CALLBACK_ARGS)
|
||||
return output_content;
|
||||
}
|
||||
|
||||
static inline std::string intToStream(unsigned long long stream)
|
||||
{
|
||||
char chrs[16] = {};
|
||||
double streamval = stream;
|
||||
int level = 0;
|
||||
while(streamval > 1024.0)
|
||||
{
|
||||
if(level >= 5)
|
||||
break;
|
||||
level++;
|
||||
streamval /= 1024.0;
|
||||
}
|
||||
switch(level)
|
||||
{
|
||||
case 3:
|
||||
snprintf(chrs, 15, "%.2f GB", streamval);
|
||||
break;
|
||||
case 4:
|
||||
snprintf(chrs, 15, "%.2f TB", streamval);
|
||||
break;
|
||||
case 5:
|
||||
snprintf(chrs, 15, "%.2f PB", streamval);
|
||||
break;
|
||||
case 2:
|
||||
snprintf(chrs, 15, "%.2f MB", streamval);
|
||||
break;
|
||||
case 1:
|
||||
snprintf(chrs, 15, "%.2f KB", streamval);
|
||||
break;
|
||||
case 0:
|
||||
snprintf(chrs, 15, "%.2f B", streamval);
|
||||
break;
|
||||
}
|
||||
return std::string(chrs);
|
||||
}
|
||||
|
||||
std::string subInfoToMessage(std::string subinfo)
|
||||
{
|
||||
typedef unsigned long long ull;
|
||||
subinfo = replace_all_distinct(subinfo, "; ", "&");
|
||||
std::string retdata, useddata = "N/A", totaldata = "N/A", expirydata = "N/A";
|
||||
std::string upload = getUrlArg(subinfo, "upload"), download = getUrlArg(subinfo, "download"), total = getUrlArg(subinfo, "total"), expire = getUrlArg(subinfo, "expire");
|
||||
ull used = to_number<ull>(upload, 0) + to_number<ull>(download, 0), tot = to_number<ull>(total, 0);
|
||||
time_t expiry = to_number<time_t>(expire, 0);
|
||||
if(used != 0)
|
||||
useddata = intToStream(used);
|
||||
if(tot != 0)
|
||||
totaldata = intToStream(tot);
|
||||
if(expiry != 0)
|
||||
{
|
||||
char buffer[30];
|
||||
struct tm *dt = localtime(&expiry);
|
||||
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M", dt);
|
||||
expirydata.assign(buffer);
|
||||
}
|
||||
if(useddata == "N/A" && totaldata == "N/A" && expirydata == "N/A")
|
||||
retdata = "Not Available";
|
||||
else
|
||||
retdata += "Stream Used: " + useddata + " Stream Total: " + totaldata + " Expiry Time: " + expirydata;
|
||||
return retdata;
|
||||
}
|
||||
|
||||
int simpleGenerator()
|
||||
{
|
||||
@@ -1740,7 +1801,7 @@ int simpleGenerator()
|
||||
|
||||
string_multimap allItems;
|
||||
std::string dummy_str;
|
||||
std::map<std::string, std::string> dummy_map;
|
||||
std::map<std::string, std::string> headers;
|
||||
int ret_code = 200;
|
||||
for(std::string &x : sections)
|
||||
{
|
||||
@@ -1758,7 +1819,7 @@ int simpleGenerator()
|
||||
if(ini.ItemExist("profile"))
|
||||
{
|
||||
profile = ini.Get("profile");
|
||||
content = getProfile("name=" + UrlEncode(profile) + "&token=" + access_token + "&expand=true", dummy_str, &ret_code, dummy_map);
|
||||
content = getProfile("name=" + UrlEncode(profile) + "&token=" + access_token + "&expand=true", dummy_str, &ret_code, headers);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1798,7 +1859,7 @@ int simpleGenerator()
|
||||
arguments += y.first + "=" + UrlEncode(y.second) + "&";
|
||||
}
|
||||
arguments.erase(arguments.size() - 1);
|
||||
content = subconverter(arguments, dummy_str, &ret_code, dummy_map);
|
||||
content = subconverter(arguments, dummy_str, &ret_code, headers);
|
||||
}
|
||||
if(ret_code != 200)
|
||||
{
|
||||
@@ -1808,7 +1869,16 @@ int simpleGenerator()
|
||||
continue;
|
||||
}
|
||||
fileWrite(path, content, true);
|
||||
for(auto &y : headers)
|
||||
{
|
||||
if(regMatch(y.first, "(?i)Subscription-UserInfo"))
|
||||
{
|
||||
std::cerr<<"User Info for artifact '"<<x<<"': "<<subInfoToMessage(y.second)<<"\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::cerr<<"Artifact '"<<x<<"' generate SUCCESS!\n\n";
|
||||
eraseElements(headers);
|
||||
}
|
||||
std::cerr<<"All artifact generated. Exiting...\n";
|
||||
return 0;
|
||||
|
||||
@@ -27,6 +27,7 @@ typedef jpcre2::select<char> jp;
|
||||
#include "misc.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
//#include <io.h>
|
||||
#include <windows.h>
|
||||
#include <winreg.h>
|
||||
|
||||
+106
-9
@@ -1,9 +1,10 @@
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#define PCRE2_CODE_UNIT_WIDTH 8
|
||||
#include <pcre2.h>
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
#include "misc.h"
|
||||
@@ -1423,14 +1424,14 @@ bool chkIgnore(const nodeInfo &node, string_array &exclude_remarks, string_array
|
||||
bool excluded = false, included = false;
|
||||
//std::string remarks = UTF8ToACP(node.remarks);
|
||||
std::string remarks = node.remarks;
|
||||
writeLog(LOG_TYPE_INFO, "Comparing exclude remarks...");
|
||||
//writeLog(LOG_TYPE_INFO, "Comparing exclude remarks...");
|
||||
excluded = std::any_of(exclude_remarks.cbegin(), exclude_remarks.cend(), [&remarks](auto &x)
|
||||
{
|
||||
return regFind(remarks, x);
|
||||
});
|
||||
if(include_remarks.size() != 0)
|
||||
{
|
||||
writeLog(LOG_TYPE_INFO, "Comparing include remarks...");
|
||||
//writeLog(LOG_TYPE_INFO, "Comparing include remarks...");
|
||||
included = std::any_of(include_remarks.cbegin(), include_remarks.cend(), [&remarks](auto &x)
|
||||
{
|
||||
return regFind(remarks, x);
|
||||
@@ -1582,8 +1583,9 @@ void explodeSub(std::string sub, bool sslibev, bool ssrlibev, std::string custom
|
||||
|
||||
void filterNodes(std::vector<nodeInfo> &nodes, string_array &exclude_remarks, string_array &include_remarks, int groupID)
|
||||
{
|
||||
int index = 0;
|
||||
int node_index = 0;
|
||||
std::vector<nodeInfo>::iterator iter = nodes.begin();
|
||||
/*
|
||||
while(iter != nodes.end())
|
||||
{
|
||||
if(chkIgnore(*iter, exclude_remarks, include_remarks))
|
||||
@@ -1594,12 +1596,92 @@ void filterNodes(std::vector<nodeInfo> &nodes, string_array &exclude_remarks, st
|
||||
else
|
||||
{
|
||||
writeLog(LOG_TYPE_INFO, "Node " + iter->group + " - " + iter->remarks + " has been added.");
|
||||
iter->id = index;
|
||||
iter->id = node_index;
|
||||
iter->groupID = groupID;
|
||||
++index;
|
||||
++node_index;
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
bool excluded = false, included = false;
|
||||
std::vector<std::unique_ptr<pcre2_code, decltype(&pcre2_code_free)>> exclude_patterns, include_patterns;
|
||||
std::vector<std::unique_ptr<pcre2_match_data, decltype(&pcre2_match_data_free)>> exclude_match_data, include_match_data;
|
||||
unsigned int i = 0;
|
||||
PCRE2_SIZE erroroffset;
|
||||
int errornumber, rc;
|
||||
|
||||
for(i = 0; i < exclude_remarks.size(); i++)
|
||||
{
|
||||
std::unique_ptr<pcre2_code, decltype(&pcre2_code_free)> pattern(pcre2_compile(reinterpret_cast<const unsigned char*>(exclude_remarks[i].c_str()), PCRE2_ZERO_TERMINATED | PCRE2_MULTILINE, 0, &errornumber, &erroroffset, NULL), &pcre2_code_free);
|
||||
if(!pattern)
|
||||
return;
|
||||
exclude_patterns.push_back(std::move(pattern));
|
||||
pcre2_jit_compile(exclude_patterns[i].get(), 0);
|
||||
std::unique_ptr<pcre2_match_data, decltype(&pcre2_match_data_free)> match_data(pcre2_match_data_create_from_pattern(exclude_patterns[i].get(), NULL), &pcre2_match_data_free);
|
||||
exclude_match_data.push_back(std::move(match_data));
|
||||
}
|
||||
for(i = 0; i < include_remarks.size(); i++)
|
||||
{
|
||||
std::unique_ptr<pcre2_code, decltype(&pcre2_code_free)> pattern(pcre2_compile(reinterpret_cast<const unsigned char*>(include_remarks[i].c_str()), PCRE2_ZERO_TERMINATED | PCRE2_MULTILINE, 0, &errornumber, &erroroffset, NULL), &pcre2_code_free);
|
||||
if(!pattern)
|
||||
return;
|
||||
include_patterns.push_back(std::move(pattern));
|
||||
pcre2_jit_compile(include_patterns[i].get(), 0);
|
||||
std::unique_ptr<pcre2_match_data, decltype(&pcre2_match_data_free)> match_data(pcre2_match_data_create_from_pattern(include_patterns[i].get(), NULL), &pcre2_match_data_free);
|
||||
include_match_data.push_back(std::move(match_data));
|
||||
}
|
||||
writeLog(LOG_TYPE_INFO, "Filter started.");
|
||||
while(iter != nodes.end())
|
||||
{
|
||||
excluded = false;
|
||||
included = false;
|
||||
for(i = 0; i < exclude_patterns.size(); i++)
|
||||
{
|
||||
rc = pcre2_match(exclude_patterns[i].get(), reinterpret_cast<const unsigned char*>(iter->remarks.c_str()), iter->remarks.size(), 0, 0, exclude_match_data[i].get(), NULL);
|
||||
if (rc < 0)
|
||||
{
|
||||
switch(rc)
|
||||
{
|
||||
case PCRE2_ERROR_NOMATCH: break;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
else
|
||||
excluded = true;
|
||||
}
|
||||
if(include_patterns.size() > 0)
|
||||
for(i = 0; i < include_patterns.size(); i++)
|
||||
{
|
||||
rc = pcre2_match(include_patterns[i].get(), reinterpret_cast<const unsigned char*>(iter->remarks.c_str()), iter->remarks.size(), 0, 0, include_match_data[i].get(), NULL);
|
||||
if (rc < 0)
|
||||
{
|
||||
switch(rc)
|
||||
{
|
||||
case PCRE2_ERROR_NOMATCH: break;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
else
|
||||
included = true;
|
||||
}
|
||||
else
|
||||
included = true;
|
||||
if(excluded || !included)
|
||||
{
|
||||
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 = node_index;
|
||||
iter->groupID = groupID;
|
||||
++node_index;
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
writeLog(LOG_TYPE_INFO, "Filter done.");
|
||||
}
|
||||
|
||||
static inline unsigned long long streamToInt(std::string stream)
|
||||
@@ -1629,12 +1711,26 @@ static inline double percentToDouble(std::string percent)
|
||||
|
||||
time_t dateStringToTimestamp(std::string date)
|
||||
{
|
||||
time_t rawtime;
|
||||
time(&rawtime);
|
||||
if(startsWith(date, "left="))
|
||||
{
|
||||
time_t seconds_left = 0;
|
||||
date.erase(0, 5);
|
||||
if(endsWith(date, "d"))
|
||||
{
|
||||
date.erase(date.size() - 1);
|
||||
seconds_left = to_number<double>(date, 0.0) * 86400.0;
|
||||
}
|
||||
return rawtime + seconds_left;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct tm *expire_time;
|
||||
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;
|
||||
@@ -1644,6 +1740,7 @@ time_t dateStringToTimestamp(std::string date)
|
||||
expire_time->tm_sec = to_int(date_array[5]);
|
||||
return mktime(expire_time);
|
||||
}
|
||||
}
|
||||
|
||||
bool getSubInfoFromHeader(std::string &header, std::string &result)
|
||||
{
|
||||
|
||||
@@ -928,6 +928,7 @@ std::string netchToSurge(std::vector<nodeInfo> &nodes, std::string &base_conf, s
|
||||
ini.store_any_line = true;
|
||||
// filter out sections that requires direct-save
|
||||
ini.AddDirectSaveSection("Rule");
|
||||
ini.AddDirectSaveSection("MITM");
|
||||
ini.AddDirectSaveSection("Script");
|
||||
ini.AddDirectSaveSection("URL Rewrite");
|
||||
ini.AddDirectSaveSection("Header Rewrite");
|
||||
|
||||
Reference in new issue
Block a user