mirror of
https://github.com/asdlokj1qpi233/subconverter.git
synced 2026-11-03 02:02:24 +00:00
Add support for using TOML as configuration file format
Add basic support for trojan-grpc nodes. Refactor codes.
This commit is contained in:
35 files changed
+2345
-531
No files matched your search
@@ -0,0 +1,361 @@
|
||||
#ifndef BINDING_H_INCLUDED
|
||||
#define BINDING_H_INCLUDED
|
||||
|
||||
#include <toml.hpp>
|
||||
|
||||
#include "crontask.h"
|
||||
#include "proxygroup.h"
|
||||
#include "regmatch.h"
|
||||
#include "ruleset.h"
|
||||
|
||||
namespace toml
|
||||
{
|
||||
template<>
|
||||
struct from<ProxyGroupConfig>
|
||||
{
|
||||
static ProxyGroupConfig from_toml(const value& v)
|
||||
{
|
||||
ProxyGroupConfig conf;
|
||||
conf.Name = toml::find<String>(v, "name");
|
||||
String type = toml::find<String>(v, "type");
|
||||
String strategy = toml::find_or<String>(v, "strategy", "");
|
||||
switch(hash_(type))
|
||||
{
|
||||
case "select"_hash:
|
||||
conf.Type = ProxyGroupType::Select;
|
||||
break;
|
||||
case "url-test"_hash:
|
||||
conf.Type = ProxyGroupType::URLTest;
|
||||
conf.Url = toml::find<String>(v, "url");
|
||||
conf.Interval = toml::find<Integer>(v, "interval");
|
||||
conf.Tolerance = toml::find_or<Integer>(v, "tolerance", 0);
|
||||
if(v.contains("lazy"))
|
||||
conf.Lazy = toml::find_or<bool>(v, "lazy", false);
|
||||
break;
|
||||
case "load-balance"_hash:
|
||||
conf.Type = ProxyGroupType::LoadBalance;
|
||||
conf.Url = toml::find<String>(v, "url");
|
||||
conf.Interval = toml::find<Integer>(v, "interval");
|
||||
switch(hash_(strategy))
|
||||
{
|
||||
case "consistent-hashing"_hash:
|
||||
conf.Strategy = BalanceStrategy::ConsistentHashing;
|
||||
break;
|
||||
case "round-robin"_hash:
|
||||
conf.Strategy = BalanceStrategy::RoundRobin;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "fallback"_hash:
|
||||
conf.Type = ProxyGroupType::Fallback;
|
||||
conf.Url = toml::find<String>(v, "url");
|
||||
conf.Interval = toml::find<Integer>(v, "interval");
|
||||
break;
|
||||
case "relay"_hash:
|
||||
conf.Type = ProxyGroupType::Relay;
|
||||
break;
|
||||
case "ssid"_hash:
|
||||
conf.Type = ProxyGroupType::SSID;
|
||||
break;
|
||||
default:
|
||||
throw toml::syntax_error("Proxy Group has incorrect type, should be one of following:\n select, url-test, load-balance, fallback, relay, ssid", v.at("type").location());
|
||||
}
|
||||
conf.Timeout = toml::find_or(v, "timeout", 5);
|
||||
conf.Proxies = toml::find_or<StrArray>(v, "rule", {});
|
||||
conf.UsingProvider = toml::find_or<StrArray>(v, "use", {});
|
||||
if(conf.Proxies.empty() && conf.UsingProvider.empty())
|
||||
throw toml::syntax_error("Proxy Group must contains at least one of proxy match rule or provider", v.location());
|
||||
if(v.contains("disable-udp"))
|
||||
conf.DisableUdp = toml::find_or(v, "disable-udp", conf.DisableUdp.get());
|
||||
return conf;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct from<RulesetConfig>
|
||||
{
|
||||
static RulesetConfig from_toml(const value& v)
|
||||
{
|
||||
RulesetConfig conf;
|
||||
conf.Group = toml::find<String>(v, "group");
|
||||
String type = toml::find_or<String>(v, "type", "surge-ruleset");
|
||||
switch(hash_(type))
|
||||
{
|
||||
/*
|
||||
case "surge-ruleset"_hash:
|
||||
conf.Type = RulesetType::SurgeRuleset;
|
||||
conf.Url = "surge:";
|
||||
break;
|
||||
case "quantumultx"_hash:
|
||||
conf.Type = RulesetType::QuantumultX;
|
||||
conf.Url = "quanx:";
|
||||
break;
|
||||
case "clash-domain"_hash:
|
||||
conf.Type = RulesetType::ClashDomain;
|
||||
conf.Url = type;
|
||||
break;
|
||||
case "clash-ipcidr"_hash:
|
||||
conf.Type = RulesetType::ClashIpCidr;
|
||||
conf.Url = type;
|
||||
break;
|
||||
case "clash-classic"_hash:
|
||||
conf.Type = RulesetType::ClashClassic;
|
||||
conf.Url = type;
|
||||
break;
|
||||
*/
|
||||
case "surge-ruleset"_hash:
|
||||
conf.Url = "surge:";
|
||||
break;
|
||||
case "quantumultx"_hash:
|
||||
conf.Url = "quanx:";
|
||||
break;
|
||||
case "clash-domain"_hash:
|
||||
case "clash-ipcidr"_hash:
|
||||
case "clash-classic"_hash:
|
||||
conf.Url = type;
|
||||
break;
|
||||
default:
|
||||
throw toml::syntax_error("Ruleset has incorrect type, should be one of following:\n surge-ruleset, quantumultx, clash-domain, clash-ipcidr, clash-classic", v.at("type").location());
|
||||
}
|
||||
conf.Url += toml::find<String>(v, "ruleset");
|
||||
conf.Interval = toml::find_or<Integer>(v, "interval", 86400);
|
||||
return conf;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct from<RegexMatchConfig>
|
||||
{
|
||||
static RegexMatchConfig from_toml(const value& v)
|
||||
{
|
||||
RegexMatchConfig conf;
|
||||
if(v.contains("script"))
|
||||
{
|
||||
conf.Script = toml::find<String>(v, "script");
|
||||
return conf;
|
||||
}
|
||||
conf.Match = toml::find<String>(v, "match");
|
||||
if(v.contains("emoji"))
|
||||
conf.Replace = toml::find<String>(v, "emoji");
|
||||
else
|
||||
conf.Replace = toml::find<String>(v, "replace");
|
||||
return conf;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct from<CronTaskConfig>
|
||||
{
|
||||
static CronTaskConfig from_toml(const value& v)
|
||||
{
|
||||
CronTaskConfig conf;
|
||||
conf.Name = toml::find<String>(v, "name");
|
||||
conf.CronExp = toml::find<String>(v, "cronexp");
|
||||
conf.Path = toml::find<String>(v, "path");
|
||||
conf.Timeout = toml::find_or<Integer>(v, "timeout", 0);
|
||||
return conf;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct from<tribool>
|
||||
{
|
||||
static tribool from_toml(const value& v)
|
||||
{
|
||||
tribool t;
|
||||
t.set(v.as_boolean());
|
||||
return t;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace INIBinding
|
||||
{
|
||||
|
||||
void parseGroupTimes(const std::string &src, int *interval, int *tolerance, int *timeout)
|
||||
{
|
||||
std::vector<int*> ptrs;
|
||||
ptrs.push_back(interval);
|
||||
ptrs.push_back(timeout);
|
||||
ptrs.push_back(tolerance);
|
||||
string_size bpos = 0, epos = src.find(",");
|
||||
for(int *x : ptrs)
|
||||
{
|
||||
if(x != NULL)
|
||||
*x = to_int(src.substr(bpos, epos - bpos), 0);
|
||||
if(epos != src.npos)
|
||||
{
|
||||
bpos = epos + 1;
|
||||
epos = src.find(",", bpos);
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
template<class T> struct from
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct from<ProxyGroupConfig>
|
||||
{
|
||||
static ProxyGroupConfigs from_ini(const StrArray &arr)
|
||||
{
|
||||
ProxyGroupConfigs confs;
|
||||
for(const String &x : arr)
|
||||
{
|
||||
unsigned int rules_upper_bound = 0;
|
||||
ProxyGroupConfig conf;
|
||||
|
||||
StrArray vArray = split(x, "`");
|
||||
if(vArray.size() < 3)
|
||||
continue;
|
||||
|
||||
conf.Name = vArray[0];
|
||||
String type = vArray[1];
|
||||
|
||||
rules_upper_bound = vArray.size();
|
||||
switch(hash_(type))
|
||||
{
|
||||
case "select"_hash:
|
||||
conf.Type = ProxyGroupType::Select;
|
||||
break;
|
||||
case "relay"_hash:
|
||||
conf.Type = ProxyGroupType::Relay;
|
||||
break;
|
||||
case "url-test"_hash:
|
||||
conf.Type = ProxyGroupType::URLTest;
|
||||
break;
|
||||
case "fallback"_hash:
|
||||
conf.Type = ProxyGroupType::Fallback;
|
||||
break;
|
||||
case "load-balance"_hash:
|
||||
conf.Type = ProxyGroupType::LoadBalance;
|
||||
break;
|
||||
case "ssid"_hash:
|
||||
conf.Type = ProxyGroupType::SSID;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
if(conf.Type == ProxyGroupType::URLTest || conf.Type == ProxyGroupType::LoadBalance || conf.Type == ProxyGroupType::Fallback)
|
||||
{
|
||||
if(rules_upper_bound < 5)
|
||||
continue;
|
||||
rules_upper_bound -= 2;
|
||||
conf.Url = vArray[rules_upper_bound];
|
||||
parseGroupTimes(vArray[rules_upper_bound + 1], &conf.Interval, &conf.Tolerance, &conf.Timeout);
|
||||
}
|
||||
|
||||
for(unsigned int i = 2; i < rules_upper_bound; i++)
|
||||
{
|
||||
if(startsWith(vArray[i], "!!PROVIDER="))
|
||||
{
|
||||
string_array list = split(vArray[i].substr(11), ",");
|
||||
conf.UsingProvider.reserve(conf.UsingProvider.size() + list.size());
|
||||
std::move(list.begin(), list.end(), std::back_inserter(conf.UsingProvider));
|
||||
}
|
||||
else
|
||||
conf.Proxies.emplace_back(std::move(vArray[i]));
|
||||
}
|
||||
confs.emplace_back(std::move(conf));
|
||||
}
|
||||
return confs;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct from<RulesetConfig>
|
||||
{
|
||||
static RulesetConfigs from_ini(const StrArray &arr)
|
||||
{
|
||||
/*
|
||||
static const std::map<std::string, RulesetType> RulesetTypes = {
|
||||
{"clash-domain:", RulesetType::ClashDomain},
|
||||
{"clash-ipcidr:", RulesetType::ClashIpCidr},
|
||||
{"clash-classic:", RulesetType::ClashClassic},
|
||||
{"quanx:", RulesetType::QuantumultX},
|
||||
{"surge:", RulesetType::SurgeRuleset}
|
||||
};
|
||||
*/
|
||||
RulesetConfigs confs;
|
||||
for(const String &x : arr)
|
||||
{
|
||||
RulesetConfig conf;
|
||||
String::size_type pos = x.find(",");
|
||||
if(pos == String::npos)
|
||||
continue;
|
||||
conf.Group = x.substr(0, pos);
|
||||
if(x.substr(pos + 1, 2) == "[]")
|
||||
{
|
||||
conf.Url = x.substr(pos + 1);
|
||||
//conf.Type = RulesetType::SurgeRuleset;
|
||||
confs.emplace_back(std::move(conf));
|
||||
continue;
|
||||
}
|
||||
String::size_type epos = x.rfind(",");
|
||||
if(pos != epos)
|
||||
{
|
||||
conf.Interval = to_int(x.substr(epos + 1), 0);
|
||||
conf.Url = x.substr(pos + 1, epos - pos - 1);
|
||||
}
|
||||
else
|
||||
conf.Url = x.substr(pos + 1);
|
||||
confs.emplace_back(std::move(conf));
|
||||
}
|
||||
return confs;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct from<CronTaskConfig>
|
||||
{
|
||||
static CronTaskConfigs from_ini(const StrArray &arr)
|
||||
{
|
||||
CronTaskConfigs confs;
|
||||
for(const String &x : arr)
|
||||
{
|
||||
CronTaskConfig conf;
|
||||
StrArray vArray = split(x, "`");
|
||||
if(vArray.size() < 3)
|
||||
continue;
|
||||
conf.Name = vArray[0];
|
||||
conf.CronExp = vArray[1];
|
||||
conf.Path = vArray[2];
|
||||
if(vArray.size() > 3)
|
||||
conf.Timeout = to_int(vArray[3], 0);
|
||||
confs.emplace_back(std::move(conf));
|
||||
}
|
||||
return confs;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct from<RegexMatchConfig>
|
||||
{
|
||||
static RegexMatchConfigs from_ini(const StrArray &arr, const std::string &delimiter)
|
||||
{
|
||||
RegexMatchConfigs confs;
|
||||
for(const String &x : arr)
|
||||
{
|
||||
RegexMatchConfig conf;
|
||||
if(startsWith(x, "script:"))
|
||||
{
|
||||
conf.Script = x.substr(7);
|
||||
confs.emplace_back(std::move(conf));
|
||||
continue;
|
||||
}
|
||||
String::size_type pos = x.rfind(delimiter);
|
||||
conf.Match = x.substr(0, pos);
|
||||
if(pos != String::npos && pos < x.size() - 1)
|
||||
conf.Replace = x.substr(pos + 1);
|
||||
confs.emplace_back(std::move(conf));
|
||||
}
|
||||
return confs;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // BINDING_H_INCLUDED
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef CRONTASK_H_INCLUDED
|
||||
#define CRONTASK_H_INCLUDED
|
||||
|
||||
#include "def.h"
|
||||
|
||||
struct CronTaskConfig
|
||||
{
|
||||
String Name;
|
||||
String CronExp;
|
||||
String Path;
|
||||
Integer Timeout = 0;
|
||||
};
|
||||
|
||||
using CronTaskConfigs = std::vector<CronTaskConfig>;
|
||||
|
||||
#endif // CRONTASK_H_INCLUDED
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef DEF_H_INCLUDED
|
||||
#define DEF_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
||||
#include "../utils/string.h"
|
||||
#include "../utils/tribool.h"
|
||||
|
||||
using String = std::string;
|
||||
using Integer = int32_t;
|
||||
using StrArray = string_array;
|
||||
using Boolean = tribool;
|
||||
|
||||
#endif // DEF_H_INCLUDED
|
||||
@@ -0,0 +1,63 @@
|
||||
#ifndef PROXYGROUP_H_INCLUDED
|
||||
#define PROXYGROUP_H_INCLUDED
|
||||
|
||||
#include "def.h"
|
||||
|
||||
enum ProxyGroupType
|
||||
{
|
||||
Select,
|
||||
URLTest,
|
||||
Fallback,
|
||||
LoadBalance,
|
||||
Relay,
|
||||
SSID
|
||||
};
|
||||
|
||||
enum BalanceStrategy
|
||||
{
|
||||
ConsistentHashing,
|
||||
RoundRobin
|
||||
};
|
||||
|
||||
struct ProxyGroupConfig
|
||||
{
|
||||
String Name;
|
||||
ProxyGroupType Type;
|
||||
StrArray Proxies;
|
||||
StrArray UsingProvider;
|
||||
String Url;
|
||||
Integer Interval = 0;
|
||||
Integer Timeout = 0;
|
||||
Integer Tolerance = 0;
|
||||
BalanceStrategy Strategy = BalanceStrategy::ConsistentHashing;
|
||||
Boolean Lazy;
|
||||
Boolean DisableUdp;
|
||||
|
||||
String TypeStr() const
|
||||
{
|
||||
switch(Type)
|
||||
{
|
||||
case ProxyGroupType::Select: return "select";
|
||||
case ProxyGroupType::URLTest: return "url-test";
|
||||
case ProxyGroupType::LoadBalance: return "load-balance";
|
||||
case ProxyGroupType::Fallback: return "fallback";
|
||||
case ProxyGroupType::Relay: return "relay";
|
||||
case ProxyGroupType::SSID: return "ssid";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
String StrategyStr() const
|
||||
{
|
||||
switch(Strategy)
|
||||
{
|
||||
case BalanceStrategy::ConsistentHashing: return "consistent-hashing";
|
||||
case BalanceStrategy::RoundRobin: return "round-robin";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
using ProxyGroupConfigs = std::vector<ProxyGroupConfig>;
|
||||
|
||||
#endif // PROXYGROUP_H_INCLUDED
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef REGMATCH_H_INCLUDED
|
||||
#define REGMATCH_H_INCLUDED
|
||||
|
||||
#include "def.h"
|
||||
|
||||
struct RegexMatchConfig
|
||||
{
|
||||
String Match;
|
||||
String Replace;
|
||||
String Script;
|
||||
};
|
||||
|
||||
using RegexMatchConfigs = std::vector<RegexMatchConfig>;
|
||||
|
||||
#endif // REGMATCH_H_INCLUDED
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef RULESET_H_INCLUDED
|
||||
#define RULESET_H_INCLUDED
|
||||
|
||||
#include "def.h"
|
||||
|
||||
enum RulesetType
|
||||
{
|
||||
SurgeRuleset,
|
||||
QuantumultX,
|
||||
ClashDomain,
|
||||
ClashIpCidr,
|
||||
ClashClassic
|
||||
};
|
||||
|
||||
struct RulesetConfig
|
||||
{
|
||||
String Group;
|
||||
//RulesetType Type = RulesetType::SurgeRuleset;
|
||||
String Url;
|
||||
Integer Interval = 86400;
|
||||
bool operator==(const RulesetConfig &r) const
|
||||
{
|
||||
return Group == r.Group && Url == r.Url && Interval == r.Interval;
|
||||
}
|
||||
};
|
||||
|
||||
using RulesetConfigs = std::vector<RulesetConfig>;
|
||||
|
||||
#endif // RULESET_H_INCLUDED
|
||||
@@ -37,8 +37,8 @@ int addNodes(std::string link, std::vector<Proxy> &allNodes, int groupID, parse_
|
||||
std::string &proxy = *parse_set.proxy, &subInfo = *parse_set.sub_info;
|
||||
string_array &exclude_remarks = *parse_set.exclude_remarks;
|
||||
string_array &include_remarks = *parse_set.include_remarks;
|
||||
string_array &stream_rules = *parse_set.stream_rules;
|
||||
string_array &time_rules = *parse_set.time_rules;
|
||||
RegexMatchConfigs &stream_rules = *parse_set.stream_rules;
|
||||
RegexMatchConfigs &time_rules = *parse_set.time_rules;
|
||||
string_icase_map &request_headers = *parse_set.request_header;
|
||||
bool &authorized = parse_set.authorized;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <limits.h>
|
||||
#include <quickjspp.hpp>
|
||||
|
||||
#include "../../config/regmatch.h"
|
||||
#include "../../parser/config/proxy.h"
|
||||
#include "../../utils/map_extra.h"
|
||||
#include "../../utils/string.h"
|
||||
@@ -15,8 +16,8 @@ struct parse_settings
|
||||
std::string *proxy = nullptr;
|
||||
string_array *exclude_remarks = nullptr;
|
||||
string_array *include_remarks = nullptr;
|
||||
string_array *stream_rules = nullptr;
|
||||
string_array *time_rules = nullptr;
|
||||
RegexMatchConfigs *stream_rules = nullptr;
|
||||
RegexMatchConfigs *time_rules = nullptr;
|
||||
std::string *sub_info = nullptr;
|
||||
bool authorized = false;
|
||||
string_icase_map *request_header = nullptr;
|
||||
|
||||
+141
-238
@@ -8,6 +8,7 @@
|
||||
#include <rapidjson/error/en.h>
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
#include "../../config/regmatch.h"
|
||||
#include "../../generator/config/subexport.h"
|
||||
#include "../../generator/template/templates.h"
|
||||
#include "../../parser/config/proxy.h"
|
||||
@@ -63,19 +64,17 @@ std::string vmessLinkConstruct(const std::string &remarks, const std::string &ad
|
||||
return sb.GetString();
|
||||
}
|
||||
|
||||
void nodeRename(Proxy &node, const string_array &rename_array, extra_settings &ext)
|
||||
void nodeRename(Proxy &node, const RegexMatchConfigs &rename_array, extra_settings &ext)
|
||||
{
|
||||
string_size pos;
|
||||
std::string match, rep;
|
||||
std::string &remark = node.Remark, original_remark = node.Remark, returned_remark, real_rule;
|
||||
|
||||
for(const std::string &x : rename_array)
|
||||
for(const RegexMatchConfig &x : rename_array)
|
||||
{
|
||||
if(startsWith(x, "!!script:"))
|
||||
if(!x.Script.empty())
|
||||
{
|
||||
script_safe_runner(ext.js_runtime, ext.js_context, [&](qjs::Context &ctx)
|
||||
{
|
||||
std::string script = x.substr(9);
|
||||
std::string script = x.Script;
|
||||
if(startsWith(script, "path:"))
|
||||
script = fileGet(script.substr(5), true);
|
||||
try
|
||||
@@ -93,14 +92,8 @@ void nodeRename(Proxy &node, const string_array &rename_array, extra_settings &e
|
||||
}, gScriptCleanContext);
|
||||
continue;
|
||||
}
|
||||
pos = x.rfind("@");
|
||||
match = x.substr(0, pos);
|
||||
if(pos != x.npos && pos < x.size())
|
||||
rep = x.substr(pos + 1);
|
||||
else
|
||||
rep.clear();
|
||||
if(applyMatcher(match, real_rule, node) && real_rule.size())
|
||||
remark = regReplace(remark, real_rule, rep);
|
||||
if(applyMatcher(x.Match, real_rule, node) && real_rule.size())
|
||||
remark = regReplace(remark, real_rule, x.Replace);
|
||||
}
|
||||
if(remark.empty())
|
||||
remark = original_remark;
|
||||
@@ -123,19 +116,18 @@ std::string removeEmoji(const std::string &orig_remark)
|
||||
return remark;
|
||||
}
|
||||
|
||||
std::string addEmoji(const Proxy &node, const string_array &emoji_array, extra_settings &ext)
|
||||
std::string addEmoji(const Proxy &node, const RegexMatchConfigs &emoji_array, extra_settings &ext)
|
||||
{
|
||||
std::string real_rule, ret;
|
||||
string_size pos;
|
||||
|
||||
for(const std::string &x : emoji_array)
|
||||
for(const RegexMatchConfig &x : emoji_array)
|
||||
{
|
||||
if(startsWith(x, "!!script:"))
|
||||
if(!x.Script.empty())
|
||||
{
|
||||
std::string result;
|
||||
script_safe_runner(ext.js_runtime, ext.js_context, [&](qjs::Context &ctx)
|
||||
{
|
||||
std::string script = x.substr(9);
|
||||
std::string script = x.Script;
|
||||
if(startsWith(script, "path:"))
|
||||
script = fileGet(script.substr(5), true);
|
||||
try
|
||||
@@ -155,11 +147,10 @@ std::string addEmoji(const Proxy &node, const string_array &emoji_array, extra_s
|
||||
return result;
|
||||
continue;
|
||||
}
|
||||
pos = x.rfind(",");
|
||||
if(pos == x.npos)
|
||||
if(x.Replace.empty())
|
||||
continue;
|
||||
if(applyMatcher(x.substr(0, pos), real_rule, node) && real_rule.size() && regFind(node.Remark, real_rule))
|
||||
return x.substr(pos + 1) + " " + node.Remark;
|
||||
if(applyMatcher(x.Match, real_rule, node) && real_rule.size() && regFind(node.Remark, real_rule))
|
||||
return x.Replace + " " + node.Remark;
|
||||
}
|
||||
return node.Remark;
|
||||
}
|
||||
@@ -206,7 +197,7 @@ void parseGroupTimes(const std::string &src, int *interval, int *tolerance, int
|
||||
return;
|
||||
}
|
||||
|
||||
void groupGenerate(std::string &rule, std::vector<Proxy> &nodelist, string_array &filtered_nodelist, bool add_direct, extra_settings &ext)
|
||||
void groupGenerate(const std::string &rule, std::vector<Proxy> &nodelist, string_array &filtered_nodelist, bool add_direct, extra_settings &ext)
|
||||
{
|
||||
std::string real_rule;
|
||||
if(startsWith(rule, "[]") && add_direct)
|
||||
@@ -291,11 +282,11 @@ void preprocessNodes(std::vector<Proxy> &nodes, extra_settings &ext)
|
||||
}
|
||||
}
|
||||
|
||||
void proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const string_array &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;
|
||||
std::vector<Proxy> nodelist;
|
||||
string_array vArray, remarks_list, filtered_nodelist;
|
||||
string_array remarks_list, filtered_nodelist;
|
||||
/// proxies style
|
||||
bool block = false, compact = false;
|
||||
switch(hash_(ext.clash_proxies_style))
|
||||
@@ -376,11 +367,11 @@ void proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const string_
|
||||
break;
|
||||
case "ws"_hash:
|
||||
singleproxy["network"] = x.TransferProtocol;
|
||||
singleproxy["ws-path"] = x.Path;
|
||||
singleproxy["ws-opts"]["path"] = x.Path;
|
||||
if(x.Host.size())
|
||||
singleproxy["ws-headers"]["Host"] = x.Host;
|
||||
singleproxy["ws-opts"]["headers"]["Host"] = x.Host;
|
||||
if(x.Edge.size())
|
||||
singleproxy["ws-headers"]["Edge"] = x.Edge;
|
||||
singleproxy["ws-opts"]["headers"]["Edge"] = x.Edge;
|
||||
break;
|
||||
case "http"_hash:
|
||||
singleproxy["network"] = x.TransferProtocol;
|
||||
@@ -472,6 +463,16 @@ void proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const string_
|
||||
singleproxy["password"].SetTag("str");
|
||||
if(!scv.is_undef())
|
||||
singleproxy["skip-cert-verify"] = scv.get();
|
||||
switch(hash_(x.TransferProtocol))
|
||||
{
|
||||
case "tcp"_hash:
|
||||
break;
|
||||
case "grpc"_hash:
|
||||
singleproxy["network"] = x.TransferProtocol;
|
||||
if(!x.Path.empty())
|
||||
singleproxy["grpc-opts"]["grpc-service-name"] = x.Path;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ProxyType::Snell:
|
||||
singleproxy["type"] = "snell";
|
||||
@@ -516,60 +517,45 @@ void proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const string_
|
||||
else
|
||||
yamlnode["Proxy"] = proxies;
|
||||
|
||||
string_array providers;
|
||||
|
||||
for(const std::string &x : extra_proxy_group)
|
||||
for(const ProxyGroupConfig &x : extra_proxy_group)
|
||||
{
|
||||
singlegroup.reset();
|
||||
eraseElements(filtered_nodelist);
|
||||
eraseElements(providers);
|
||||
unsigned int rules_upper_bound = 0;
|
||||
|
||||
vArray = split(x, "`");
|
||||
if(vArray.size() < 3)
|
||||
continue;
|
||||
singlegroup["name"] = x.Name;
|
||||
singlegroup["type"] = x.TypeStr();
|
||||
|
||||
singlegroup["name"] = vArray[0];
|
||||
singlegroup["type"] = vArray[1];
|
||||
|
||||
int interval = 0, tolerance = 0;
|
||||
rules_upper_bound = vArray.size();
|
||||
switch(hash_(vArray[1]))
|
||||
switch(x.Type)
|
||||
{
|
||||
case "select"_hash:
|
||||
case "relay"_hash:
|
||||
case ProxyGroupType::Select:
|
||||
case ProxyGroupType::Relay:
|
||||
break;
|
||||
case "url-test"_hash:
|
||||
case "fallback"_hash:
|
||||
case "load-balance"_hash:
|
||||
if(rules_upper_bound < 5)
|
||||
continue;
|
||||
rules_upper_bound -= 2;
|
||||
singlegroup["url"] = vArray[rules_upper_bound];
|
||||
parseGroupTimes(vArray[rules_upper_bound + 1], &interval, &tolerance, NULL);
|
||||
if(interval)
|
||||
singlegroup["interval"] = interval;
|
||||
if(tolerance)
|
||||
singlegroup["tolerance"] = tolerance;
|
||||
case ProxyGroupType::LoadBalance:
|
||||
singlegroup["strategy"] = x.StrategyStr();
|
||||
[[fallthrough]];
|
||||
case ProxyGroupType::URLTest:
|
||||
if(!x.Lazy.is_undef())
|
||||
singlegroup["lazy"] = x.Lazy.get();
|
||||
[[fallthrough]];
|
||||
case ProxyGroupType::Fallback:
|
||||
singlegroup["url"] = x.Url;
|
||||
if(x.Interval > 0)
|
||||
singlegroup["interval"] = x.Interval;
|
||||
if(x.Tolerance > 0)
|
||||
singlegroup["tolerance"] = x.Tolerance;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
if(!x.DisableUdp.is_undef())
|
||||
singlegroup["disable-udp"] = x.DisableUdp.get();
|
||||
|
||||
for(unsigned int i = 2; i < rules_upper_bound; i++)
|
||||
{
|
||||
if(startsWith(vArray[i], "!!PROVIDER="))
|
||||
{
|
||||
string_array list = split(vArray[i].substr(11), ",");
|
||||
providers.reserve(providers.size() + list.size());
|
||||
std::move(list.begin(), list.end(), std::back_inserter(providers));
|
||||
}
|
||||
else
|
||||
groupGenerate(vArray[i], nodelist, filtered_nodelist, true, ext);
|
||||
}
|
||||
for(const auto& y : x.Proxies)
|
||||
groupGenerate(y, nodelist, filtered_nodelist, true, ext);
|
||||
|
||||
if(providers.size())
|
||||
singlegroup["use"] = providers;
|
||||
if(x.UsingProvider.size())
|
||||
singlegroup["use"] = x.UsingProvider;
|
||||
else
|
||||
{
|
||||
if(filtered_nodelist.empty())
|
||||
@@ -582,7 +568,7 @@ void proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const string_
|
||||
bool replace_flag = false;
|
||||
for(unsigned int i = 0; i < original_groups.size(); i++)
|
||||
{
|
||||
if(original_groups[i]["name"].as<std::string>() == vArray[0])
|
||||
if(original_groups[i]["name"].as<std::string>() == x.Name)
|
||||
{
|
||||
original_groups[i] = singlegroup;
|
||||
replace_flag = true;
|
||||
@@ -599,7 +585,7 @@ void proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const string_
|
||||
yamlnode["Proxy Group"] = original_groups;
|
||||
}
|
||||
|
||||
std::string proxyToClash(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, const string_array &extra_proxy_group, bool clashR, extra_settings &ext)
|
||||
std::string proxyToClash(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, bool clashR, extra_settings &ext)
|
||||
{
|
||||
YAML::Node yamlnode;
|
||||
|
||||
@@ -647,7 +633,7 @@ std::string proxyToClash(std::vector<Proxy> &nodes, const std::string &base_conf
|
||||
return output_content;
|
||||
}
|
||||
|
||||
std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, const string_array &extra_proxy_group, int surge_ver, extra_settings &ext)
|
||||
std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, int surge_ver, extra_settings &ext)
|
||||
{
|
||||
INIReader ini;
|
||||
std::string proxy;
|
||||
@@ -656,7 +642,7 @@ std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf
|
||||
std::vector<Proxy> nodelist;
|
||||
unsigned short local_port = 1080;
|
||||
|
||||
string_array vArray, remarks_list, filtered_nodelist, args;
|
||||
string_array remarks_list, filtered_nodelist, args;
|
||||
|
||||
ini.store_any_line = true;
|
||||
// filter out sections that requires direct-save
|
||||
@@ -833,53 +819,35 @@ std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf
|
||||
|
||||
ini.SetCurrentSection("Proxy Group");
|
||||
ini.EraseSection();
|
||||
for(const std::string &x : extra_proxy_group)
|
||||
for(const ProxyGroupConfig &x : extra_proxy_group)
|
||||
{
|
||||
//group pref
|
||||
std::string url;
|
||||
int interval = 0, tolerance = 0, timeout = 0;
|
||||
eraseElements(filtered_nodelist);
|
||||
unsigned int rules_upper_bound = 0;
|
||||
url.clear();
|
||||
proxy.clear();
|
||||
|
||||
vArray = split(x, "`");
|
||||
if(vArray.size() < 3)
|
||||
continue;
|
||||
|
||||
rules_upper_bound = vArray.size();
|
||||
switch(hash_(vArray[1]))
|
||||
switch(x.Type)
|
||||
{
|
||||
case "select"_hash:
|
||||
case ProxyGroupType::Select:
|
||||
case ProxyGroupType::URLTest:
|
||||
case ProxyGroupType::Fallback:
|
||||
break;
|
||||
case "load-balance"_hash:
|
||||
case ProxyGroupType::LoadBalance:
|
||||
if(surge_ver < 1)
|
||||
continue;
|
||||
[[fallthrough]];
|
||||
case "url-test"_hash:
|
||||
case "fallback"_hash:
|
||||
if(rules_upper_bound < 5)
|
||||
continue;
|
||||
rules_upper_bound -= 2;
|
||||
url = vArray[rules_upper_bound];
|
||||
parseGroupTimes(vArray[rules_upper_bound + 1], &interval, &tolerance, &timeout);
|
||||
break;
|
||||
case "ssid"_hash:
|
||||
if(rules_upper_bound < 4)
|
||||
continue;
|
||||
proxy = vArray[1] + ",default=" + vArray[2] + ",";
|
||||
proxy += std::accumulate(vArray.begin() + 4, vArray.end(), vArray[3], [](std::string a, std::string b)
|
||||
case ProxyGroupType::SSID:
|
||||
proxy = x.TypeStr() + ",default=" + x.Proxies[0] + ",";
|
||||
proxy += std::accumulate(x.Proxies.begin() + 2, x.Proxies.end(), x.Proxies[1], [](std::string a, std::string b)
|
||||
{
|
||||
return std::move(a) + "," + std::move(b);
|
||||
});
|
||||
ini.Set("{NONAME}", vArray[0] + " = " + proxy); //insert order
|
||||
ini.Set("{NONAME}", x.Name + " = " + proxy); //insert order
|
||||
continue;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
for(unsigned int i = 2; i < rules_upper_bound; i++)
|
||||
groupGenerate(vArray[i], nodelist, filtered_nodelist, true, ext);
|
||||
for(const auto &y : x.Proxies)
|
||||
groupGenerate(y, nodelist, filtered_nodelist, true, ext);
|
||||
|
||||
if(!filtered_nodelist.size())
|
||||
filtered_nodelist.emplace_back("DIRECT");
|
||||
@@ -892,28 +860,28 @@ std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf
|
||||
case "direct"_hash:
|
||||
case "reject"_hash:
|
||||
case "reject-tinygif"_hash:
|
||||
ini.Set("Proxy", "{NONAME}", vArray[0] + " = " + proxy);
|
||||
ini.Set("Proxy", "{NONAME}", x.Name + " = " + proxy);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
proxy = vArray[1] + ",";
|
||||
proxy = x.TypeStr() + ",";
|
||||
proxy += std::accumulate(std::next(filtered_nodelist.cbegin()), filtered_nodelist.cend(), filtered_nodelist[0], [](std::string a, std::string b)
|
||||
{
|
||||
return std::move(a) + "," + std::move(b);
|
||||
});
|
||||
if(vArray[1] == "url-test" || vArray[1] == "fallback")
|
||||
if(x.Type == ProxyGroupType::URLTest || x.Type == ProxyGroupType::Fallback)
|
||||
{
|
||||
proxy += ",url=" + url + ",interval=" + std::to_string(interval);
|
||||
if(tolerance > 0)
|
||||
proxy += ",tolerance=" + std::to_string(tolerance);
|
||||
if(timeout > 0)
|
||||
proxy += ",timeout=" + std::to_string(timeout);
|
||||
proxy += ",url=" + x.Url + ",interval=" + std::to_string(x.Interval);
|
||||
if(x.Tolerance > 0)
|
||||
proxy += ",tolerance=" + std::to_string(x.Tolerance);
|
||||
if(x.Timeout > 0)
|
||||
proxy += ",timeout=" + std::to_string(x.Timeout);
|
||||
}
|
||||
else if(vArray[1] == "load-balance")
|
||||
proxy += ",url=" + url;
|
||||
else if(x.Type == ProxyGroupType::LoadBalance)
|
||||
proxy += ",url=" + x.Url;
|
||||
|
||||
ini.Set("{NONAME}", vArray[0] + " = " + proxy); //insert order
|
||||
ini.Set("{NONAME}", x.Name + " = " + proxy); //insert order
|
||||
}
|
||||
|
||||
if(ext.enable_rule_generator)
|
||||
@@ -1075,7 +1043,7 @@ std::string proxyToSSSub(std::string base_conf, std::vector<Proxy> &nodes, extra
|
||||
return output_content;
|
||||
}
|
||||
|
||||
std::string proxyToQuan(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, const string_array &extra_proxy_group, extra_settings &ext)
|
||||
std::string proxyToQuan(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext)
|
||||
{
|
||||
INIReader ini;
|
||||
ini.store_any_line = true;
|
||||
@@ -1102,7 +1070,7 @@ std::string proxyToQuan(std::vector<Proxy> &nodes, const std::string &base_conf,
|
||||
return ini.ToString();
|
||||
}
|
||||
|
||||
void proxyToQuan(std::vector<Proxy> &nodes, INIReader &ini, std::vector<ruleset_content> &ruleset_content_array, const string_array &extra_proxy_group, extra_settings &ext)
|
||||
void proxyToQuan(std::vector<Proxy> &nodes, INIReader &ini, std::vector<ruleset_content> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext)
|
||||
{
|
||||
std::string type, proxyStr;
|
||||
tribool scv;
|
||||
@@ -1244,47 +1212,27 @@ void proxyToQuan(std::vector<Proxy> &nodes, INIReader &ini, std::vector<ruleset_
|
||||
|
||||
std::string singlegroup;
|
||||
std::string name, proxies;
|
||||
string_array vArray;
|
||||
for(const std::string &x : extra_proxy_group)
|
||||
for(const ProxyGroupConfig &x : extra_proxy_group)
|
||||
{
|
||||
eraseElements(filtered_nodelist);
|
||||
unsigned int rules_upper_bound = 0;
|
||||
|
||||
vArray = split(x, "`");
|
||||
if(vArray.size() < 3)
|
||||
continue;
|
||||
|
||||
rules_upper_bound = vArray.size();
|
||||
switch(hash_(vArray[1]))
|
||||
switch(x.Type)
|
||||
{
|
||||
case "select"_hash:
|
||||
case ProxyGroupType::Select:
|
||||
case ProxyGroupType::Fallback:
|
||||
type = "static";
|
||||
break;
|
||||
case "fallback"_hash:
|
||||
type = "static";
|
||||
if(vArray.size() < 5)
|
||||
continue;
|
||||
rules_upper_bound -= 2;
|
||||
break;
|
||||
case "url-test"_hash:
|
||||
case ProxyGroupType::URLTest:
|
||||
type = "auto";
|
||||
if(vArray.size() < 5)
|
||||
continue;
|
||||
rules_upper_bound -= 2;
|
||||
break;
|
||||
case "load-balance"_hash:
|
||||
case ProxyGroupType::LoadBalance:
|
||||
type = "balance, round-robin";
|
||||
if(vArray.size() < 5)
|
||||
continue;
|
||||
rules_upper_bound -= 2;
|
||||
break;
|
||||
case "ssid"_hash:
|
||||
case ProxyGroupType::SSID:
|
||||
{
|
||||
if(rules_upper_bound < 4)
|
||||
continue;
|
||||
singlegroup = vArray[0] + " : wifi = " + vArray[2];
|
||||
singlegroup = x.Name + " : wifi = " + x.Proxies[0];
|
||||
std::string content, celluar, celluar_matcher = R"(^(.*?),?celluar\s?=\s?(.*?)(,.*)$)", rem_a, rem_b;
|
||||
for(auto iter = vArray.begin() + 3; iter != vArray.end(); iter++)
|
||||
for(auto iter = x.Proxies.begin() + 1; iter != x.Proxies.end(); iter++)
|
||||
{
|
||||
if(regGetMatch(*iter, celluar_matcher, 4, 0, &rem_a, &celluar, &rem_b))
|
||||
{
|
||||
@@ -1303,10 +1251,8 @@ void proxyToQuan(std::vector<Proxy> &nodes, INIReader &ini, std::vector<ruleset_
|
||||
continue;
|
||||
}
|
||||
|
||||
name = vArray[0];
|
||||
|
||||
for(unsigned int i = 2; i < rules_upper_bound; i++)
|
||||
groupGenerate(vArray[i], nodelist, filtered_nodelist, true, ext);
|
||||
for(const auto &y : x.Proxies)
|
||||
groupGenerate(y, nodelist, filtered_nodelist, true, ext);
|
||||
|
||||
if(!filtered_nodelist.size())
|
||||
filtered_nodelist.emplace_back("direct");
|
||||
@@ -1319,7 +1265,7 @@ void proxyToQuan(std::vector<Proxy> &nodes, INIReader &ini, std::vector<ruleset_
|
||||
return std::move(a) + "\n" + std::move(b);
|
||||
});
|
||||
|
||||
singlegroup = name + " : " + type;
|
||||
singlegroup = x.Name + " : " + type;
|
||||
if(type == "static")
|
||||
singlegroup += ", " + filtered_nodelist[0];
|
||||
singlegroup += "\n" + proxies + "\n";
|
||||
@@ -1330,7 +1276,7 @@ void proxyToQuan(std::vector<Proxy> &nodes, INIReader &ini, std::vector<ruleset_
|
||||
rulesetToSurge(ini, ruleset_content_array, -2, ext.overwrite_original_rules, std::string());
|
||||
}
|
||||
|
||||
std::string proxyToQuanX(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, const string_array &extra_proxy_group, extra_settings &ext)
|
||||
std::string proxyToQuanX(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext)
|
||||
{
|
||||
INIReader ini;
|
||||
ini.store_any_line = true;
|
||||
@@ -1364,7 +1310,7 @@ std::string proxyToQuanX(std::vector<Proxy> &nodes, const std::string &base_conf
|
||||
return ini.ToString();
|
||||
}
|
||||
|
||||
void proxyToQuanX(std::vector<Proxy> &nodes, INIReader &ini, std::vector<ruleset_content> &ruleset_content_array, const string_array &extra_proxy_group, extra_settings &ext)
|
||||
void proxyToQuanX(std::vector<Proxy> &nodes, INIReader &ini, std::vector<ruleset_content> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext)
|
||||
{
|
||||
std::string type;
|
||||
std::string remark, hostname, port, method;
|
||||
@@ -1503,53 +1449,37 @@ void proxyToQuanX(std::vector<Proxy> &nodes, INIReader &ini, std::vector<ruleset
|
||||
ini.EraseSection();
|
||||
|
||||
std::string singlegroup;
|
||||
std::string name, proxies;
|
||||
std::string proxies;
|
||||
string_array vArray;
|
||||
for(const std::string &x : extra_proxy_group)
|
||||
for(const ProxyGroupConfig &x : extra_proxy_group)
|
||||
{
|
||||
eraseElements(filtered_nodelist);
|
||||
unsigned int rules_upper_bound = 0;
|
||||
|
||||
vArray = split(x, "`");
|
||||
if(vArray.size() < 3)
|
||||
continue;
|
||||
|
||||
rules_upper_bound = vArray.size();
|
||||
switch(hash_(vArray[1]))
|
||||
switch(x.Type)
|
||||
{
|
||||
case "select"_hash:
|
||||
case ProxyGroupType::Select:
|
||||
type = "static";
|
||||
break;
|
||||
case "url-test"_hash:
|
||||
case "fallback"_hash:
|
||||
case ProxyGroupType::URLTest:
|
||||
case ProxyGroupType::Fallback:
|
||||
type = "available";
|
||||
if(rules_upper_bound < 5)
|
||||
continue;
|
||||
rules_upper_bound -= 2;
|
||||
break;
|
||||
case "load-balance"_hash:
|
||||
case ProxyGroupType::LoadBalance:
|
||||
type = "round-robin";
|
||||
if(rules_upper_bound < 5)
|
||||
continue;
|
||||
rules_upper_bound -= 2;
|
||||
break;
|
||||
case "ssid"_hash:
|
||||
if(rules_upper_bound < 4)
|
||||
continue;
|
||||
case ProxyGroupType::SSID:
|
||||
type = "ssid";
|
||||
for(auto iter = vArray.begin() + 2; iter != vArray.end(); iter++)
|
||||
for(auto iter = x.Proxies.begin(); iter != x.Proxies.end(); iter++)
|
||||
filtered_nodelist.emplace_back(replaceAllDistinct(*iter, "=", ":"));
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
name = vArray[0];
|
||||
|
||||
if(hash_(vArray[1]) != "ssid"_hash)
|
||||
if(x.Type != ProxyGroupType::SSID)
|
||||
{
|
||||
for(unsigned int i = 2; i < rules_upper_bound; i++)
|
||||
groupGenerate(vArray[i], nodelist, filtered_nodelist, true, ext);
|
||||
for(const auto &y : x.Proxies)
|
||||
groupGenerate(y, nodelist, filtered_nodelist, true, ext);
|
||||
|
||||
if(!filtered_nodelist.size())
|
||||
filtered_nodelist.emplace_back("direct");
|
||||
@@ -1558,12 +1488,12 @@ void proxyToQuanX(std::vector<Proxy> &nodes, INIReader &ini, std::vector<ruleset
|
||||
type = "static";
|
||||
}
|
||||
|
||||
auto iter = std::find_if(original_groups.begin(), original_groups.end(), [name](const string_multimap::value_type &n)
|
||||
auto iter = std::find_if(original_groups.begin(), original_groups.end(), [&](const string_multimap::value_type &n)
|
||||
{
|
||||
std::string groupdata = n.second;
|
||||
std::string::size_type cpos = groupdata.find(",");
|
||||
if(cpos != groupdata.npos)
|
||||
return trim(groupdata.substr(0, cpos)) == name;
|
||||
return trim(groupdata.substr(0, cpos)) == x.Name;
|
||||
else
|
||||
return false;
|
||||
});
|
||||
@@ -1582,7 +1512,7 @@ void proxyToQuanX(std::vector<Proxy> &nodes, INIReader &ini, std::vector<ruleset
|
||||
return std::move(a) + ", " + std::move(b);
|
||||
});
|
||||
|
||||
singlegroup = type + "=" + name + ", " + proxies;
|
||||
singlegroup = type + "=" + x.Name + ", " + proxies;
|
||||
ini.Set("{NONAME}", singlegroup);
|
||||
}
|
||||
|
||||
@@ -1745,7 +1675,7 @@ std::string proxyToSSD(std::vector<Proxy> &nodes, std::string &group, std::strin
|
||||
return "ssd://" + base64Encode(sb.GetString());
|
||||
}
|
||||
|
||||
std::string proxyToMellow(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, const string_array &extra_proxy_group, extra_settings &ext)
|
||||
std::string proxyToMellow(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext)
|
||||
{
|
||||
INIReader ini;
|
||||
ini.store_any_line = true;
|
||||
@@ -1760,7 +1690,7 @@ std::string proxyToMellow(std::vector<Proxy> &nodes, const std::string &base_con
|
||||
return ini.ToString();
|
||||
}
|
||||
|
||||
void proxyToMellow(std::vector<Proxy> &nodes, INIReader &ini, std::vector<ruleset_content> &ruleset_content_array, const string_array &extra_proxy_group, extra_settings &ext)
|
||||
void proxyToMellow(std::vector<Proxy> &nodes, INIReader &ini, std::vector<ruleset_content> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext)
|
||||
{
|
||||
std::string proxy;
|
||||
std::string type, remark, hostname, port, username, password, method;
|
||||
@@ -1849,36 +1779,25 @@ void proxyToMellow(std::vector<Proxy> &nodes, INIReader &ini, std::vector<rulese
|
||||
|
||||
ini.SetCurrentSection("EndpointGroup");
|
||||
|
||||
for(const std::string &x : extra_proxy_group)
|
||||
for(const ProxyGroupConfig &x : extra_proxy_group)
|
||||
{
|
||||
eraseElements(filtered_nodelist);
|
||||
unsigned int rules_upper_bound = 0;
|
||||
url.clear();
|
||||
proxy.clear();
|
||||
|
||||
vArray = split(x, "`");
|
||||
if(vArray.size() < 3)
|
||||
continue;
|
||||
|
||||
rules_upper_bound = vArray.size();
|
||||
switch(hash_(vArray[1]))
|
||||
switch(x.Type)
|
||||
{
|
||||
case "select"_hash:
|
||||
break;
|
||||
case "url-test"_hash:
|
||||
case "fallback"_hash:
|
||||
case "load-balance"_hash:
|
||||
if(vArray.size() < 5)
|
||||
continue;
|
||||
rules_upper_bound -= 2;
|
||||
url = vArray[vArray.size() - 2];
|
||||
case ProxyGroupType::Select:
|
||||
case ProxyGroupType::URLTest:
|
||||
case ProxyGroupType::Fallback:
|
||||
case ProxyGroupType::LoadBalance:
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
for(unsigned int i = 2; i < rules_upper_bound; i++)
|
||||
groupGenerate(vArray[i], nodelist, filtered_nodelist, false, ext);
|
||||
for(const auto &y : x.Proxies)
|
||||
groupGenerate(y, nodelist, filtered_nodelist, false, ext);
|
||||
|
||||
if(!filtered_nodelist.size())
|
||||
{
|
||||
@@ -1897,7 +1816,7 @@ void proxyToMellow(std::vector<Proxy> &nodes, INIReader &ini, std::vector<rulese
|
||||
proxy += ",url=" + url;
|
||||
*/
|
||||
|
||||
proxy = vArray[0] + ", ";
|
||||
proxy = x.Name + ", ";
|
||||
/*
|
||||
for(std::string &y : filtered_nodelist)
|
||||
proxy += y + ":";
|
||||
@@ -1916,7 +1835,7 @@ void proxyToMellow(std::vector<Proxy> &nodes, INIReader &ini, std::vector<rulese
|
||||
rulesetToSurge(ini, ruleset_content_array, 0, ext.overwrite_original_rules, std::string());
|
||||
}
|
||||
|
||||
std::string proxyToLoon(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, const string_array &extra_proxy_group, extra_settings &ext)
|
||||
std::string proxyToLoon(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext)
|
||||
{
|
||||
rapidjson::Document json;
|
||||
INIReader ini;
|
||||
@@ -1924,9 +1843,6 @@ std::string proxyToLoon(std::vector<Proxy> &nodes, const std::string &base_conf,
|
||||
std::string output_nodelist;
|
||||
tribool scv;
|
||||
std::vector<Proxy> nodelist;
|
||||
//group pref
|
||||
std::string url;
|
||||
int interval = 0;
|
||||
|
||||
string_array vArray, remarks_list, filtered_nodelist;
|
||||
|
||||
@@ -2039,51 +1955,38 @@ std::string proxyToLoon(std::vector<Proxy> &nodes, const std::string &base_conf,
|
||||
|
||||
ini.SetCurrentSection("Proxy Group");
|
||||
ini.EraseSection();
|
||||
for(const std::string &x : extra_proxy_group)
|
||||
for(const ProxyGroupConfig &x : extra_proxy_group)
|
||||
{
|
||||
eraseElements(filtered_nodelist);
|
||||
unsigned int rules_upper_bound = 0;
|
||||
url.clear();
|
||||
proxy.clear();
|
||||
|
||||
vArray = split(x, "`");
|
||||
if(vArray.size() < 3)
|
||||
continue;
|
||||
|
||||
rules_upper_bound = vArray.size();
|
||||
switch(hash_(vArray[1]))
|
||||
switch(x.Type)
|
||||
{
|
||||
case "select"_hash:
|
||||
case ProxyGroupType::Select:
|
||||
case ProxyGroupType::URLTest:
|
||||
case ProxyGroupType::Fallback:
|
||||
break;
|
||||
case "url-test"_hash:
|
||||
case "fallback"_hash:
|
||||
if(vArray.size() < 5)
|
||||
case ProxyGroupType::SSID:
|
||||
if(x.Proxies.size() < 2)
|
||||
continue;
|
||||
rules_upper_bound -= 2;
|
||||
url = vArray[rules_upper_bound];
|
||||
parseGroupTimes(vArray[rules_upper_bound + 1], &interval, NULL, NULL);
|
||||
break;
|
||||
case "ssid"_hash:
|
||||
if(vArray.size() < 4)
|
||||
continue;
|
||||
proxy = vArray[1] + ",default=" + vArray[2] + ",";
|
||||
proxy += std::accumulate(vArray.begin() + 4, vArray.end(), vArray[3], [](std::string a, std::string b)
|
||||
proxy = x.TypeStr() + ",default=" + x.Proxies[0] + ",";
|
||||
proxy += std::accumulate(x.Proxies.begin() + 2, x.Proxies.end(), vArray[1], [](std::string a, std::string b)
|
||||
{
|
||||
return std::move(a) + "," + std::move(b);
|
||||
});
|
||||
ini.Set("{NONAME}", vArray[0] + " = " + proxy); //insert order
|
||||
ini.Set("{NONAME}", x.Name + " = " + proxy); //insert order
|
||||
continue;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
for(unsigned int i = 2; i < rules_upper_bound; i++)
|
||||
groupGenerate(vArray[i], nodelist, filtered_nodelist, true, ext);
|
||||
for(const auto &y : x.Proxies)
|
||||
groupGenerate(y, nodelist, filtered_nodelist, true, ext);
|
||||
|
||||
if(!filtered_nodelist.size())
|
||||
filtered_nodelist.emplace_back("DIRECT");
|
||||
|
||||
proxy = vArray[1] + ",";
|
||||
proxy = x.TypeStr() + ",";
|
||||
/*
|
||||
for(std::string &y : filtered_nodelist)
|
||||
proxy += "," + y;
|
||||
@@ -2092,10 +1995,10 @@ std::string proxyToLoon(std::vector<Proxy> &nodes, const std::string &base_conf,
|
||||
{
|
||||
return std::move(a) + "," + std::move(b);
|
||||
});
|
||||
if(vArray[1] == "url-test" || vArray[1] == "fallback")
|
||||
proxy += ",url=" + url + ",interval=" + std::to_string(interval);
|
||||
if(x.Type == ProxyGroupType::URLTest || x.Type == ProxyGroupType::Fallback)
|
||||
proxy += ",url=" + x.Url + ",interval=" + std::to_string(x.Interval);
|
||||
|
||||
ini.Set("{NONAME}", vArray[0] + " = " + proxy); //insert order
|
||||
ini.Set("{NONAME}", x.Name + " = " + proxy); //insert order
|
||||
}
|
||||
|
||||
if(ext.enable_rule_generator)
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
#include <quickjspp.hpp>
|
||||
|
||||
#include "../../config/proxygroup.h"
|
||||
#include "../../config/regmatch.h"
|
||||
#include "../../parser/config/proxy.h"
|
||||
#include "../../utils/ini_reader/ini_reader.h"
|
||||
#include "../../utils/string.h"
|
||||
@@ -15,8 +17,8 @@ struct extra_settings
|
||||
{
|
||||
bool enable_rule_generator = true;
|
||||
bool overwrite_original_rules = true;
|
||||
string_array rename_array;
|
||||
string_array emoji_array;
|
||||
RegexMatchConfigs rename_array;
|
||||
RegexMatchConfigs emoji_array;
|
||||
bool add_emoji = false;
|
||||
bool remove_emoji = false;
|
||||
bool append_proxy_type = false;
|
||||
@@ -52,18 +54,18 @@ void rulesetToClash(YAML::Node &base_rule, std::vector<ruleset_content> &ruleset
|
||||
void rulesetToSurge(INIReader &base_rule, std::vector<ruleset_content> &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<ruleset_content> &ruleset_content_array, const string_array &extra_proxy_group, bool clashR, extra_settings &ext);
|
||||
void proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const string_array &extra_proxy_group, bool clashR, extra_settings &ext);
|
||||
std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, const string_array &extra_proxy_group, int surge_ver, extra_settings &ext);
|
||||
std::string proxyToMellow(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, const string_array &extra_proxy_group, extra_settings &ext);
|
||||
void proxyToMellow(std::vector<Proxy> &nodes, INIReader &ini, std::vector<ruleset_content> &ruleset_content_array, const string_array &extra_proxy_group, extra_settings &ext);
|
||||
std::string proxyToLoon(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, const string_array &extra_proxy_group, extra_settings &ext);
|
||||
std::string proxyToClash(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &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);
|
||||
std::string proxyToSurge(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, int surge_ver, extra_settings &ext);
|
||||
std::string proxyToMellow(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext);
|
||||
void proxyToMellow(std::vector<Proxy> &nodes, INIReader &ini, std::vector<ruleset_content> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext);
|
||||
std::string proxyToLoon(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext);
|
||||
std::string proxyToSSSub(std::string base_conf, std::vector<Proxy> &nodes, extra_settings &ext);
|
||||
std::string proxyToSingle(std::vector<Proxy> &nodes, int types, extra_settings &ext);
|
||||
std::string proxyToQuanX(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, const string_array &extra_proxy_group, extra_settings &ext);
|
||||
void proxyToQuanX(std::vector<Proxy> &nodes, INIReader &ini, std::vector<ruleset_content> &ruleset_content_array, const string_array &extra_proxy_group, extra_settings &ext);
|
||||
std::string proxyToQuan(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, const string_array &extra_proxy_group, extra_settings &ext);
|
||||
void proxyToQuan(std::vector<Proxy> &nodes, INIReader &ini, std::vector<ruleset_content> &ruleset_content_array, const string_array &extra_proxy_group, extra_settings &ext);
|
||||
std::string proxyToQuanX(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext);
|
||||
void proxyToQuanX(std::vector<Proxy> &nodes, INIReader &ini, std::vector<ruleset_content> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext);
|
||||
std::string proxyToQuan(std::vector<Proxy> &nodes, const std::string &base_conf, std::vector<ruleset_content> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext);
|
||||
void proxyToQuan(std::vector<Proxy> &nodes, INIReader &ini, std::vector<ruleset_content> &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext);
|
||||
std::string proxyToSSD(std::vector<Proxy> &nodes, std::string &group, std::string &userinfo, extra_settings &ext);
|
||||
|
||||
#endif // SUBEXPORT_H_INCLUDED
|
||||
+475
-97
@@ -6,6 +6,7 @@
|
||||
#include <inja.hpp>
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
#include "../config/binding.h"
|
||||
#include "../generator/config/ruleconvert.h"
|
||||
#include "../generator/config/nodemanip.h"
|
||||
#include "../generator/config/ruleconvert.h"
|
||||
@@ -33,7 +34,9 @@
|
||||
|
||||
//common settings
|
||||
std::string gPrefPath = "pref.ini", gDefaultExtConfig;
|
||||
string_array gExcludeRemarks, gIncludeRemarks, gCustomRulesets, gStreamNodeRules, gTimeNodeRules;
|
||||
string_array gExcludeRemarks, gIncludeRemarks;
|
||||
RulesetConfigs gCustomRulesets;
|
||||
RegexMatchConfigs gStreamNodeRules, gTimeNodeRules;
|
||||
std::vector<ruleset_content> gRulesetContent;
|
||||
std::string gListenAddress = "127.0.0.1", gDefaultUrls, gInsertUrls, gManagedConfigPrefix;
|
||||
int gListenPort = 25500, gMaxPendingConns = 10, gMaxConcurThreads = 4;
|
||||
@@ -46,9 +49,6 @@ extern int gLogLevel;
|
||||
extern long gMaxAllowedDownloadSize;
|
||||
string_map gAliases;
|
||||
|
||||
extern bool gServeFile;
|
||||
extern std::string gServeFileRoot;
|
||||
|
||||
//global variables for template
|
||||
std::string gTemplatePath = "templates";
|
||||
string_map gTemplateVars;
|
||||
@@ -61,7 +61,7 @@ std::string gGenerateProfiles;
|
||||
std::mutex gMutexConfigure;
|
||||
|
||||
//preferences
|
||||
string_array gRenames, gEmojis;
|
||||
RegexMatchConfigs gRenames, gEmojis;
|
||||
bool gAddEmoji = false, gRemoveEmoji = false, gAppendType = false, gFilterDeprecated = true;
|
||||
tribool gUDP, gTFO, gSkipCertVerify, gTLS13, gEnableInsert;
|
||||
bool gEnableSort = false, gUpdateStrict = false;
|
||||
@@ -72,7 +72,7 @@ int gUpdateInterval = 0;
|
||||
std::string gSortScript, gFilterScript;
|
||||
|
||||
std::string gClashBase;
|
||||
string_array gCustomProxyGroups;
|
||||
ProxyGroupConfigs gCustomProxyGroups;
|
||||
std::string gSurgeBase, gSurfboardBase, gMellowBase, gQuanBase, gQuanXBase, gLoonBase, gSSSubBase;
|
||||
std::string gSurgeSSRPath, gQuanXDevID;
|
||||
|
||||
@@ -86,11 +86,13 @@ bool gScriptCleanContext = false;
|
||||
|
||||
//cron system
|
||||
bool gEnableCron = false;
|
||||
string_array gCronTasks;
|
||||
CronTaskConfigs gCronTasks;
|
||||
|
||||
extern WebServer webServer;
|
||||
|
||||
string_array gRegexBlacklist = {"(.*)*"};
|
||||
|
||||
void refreshRulesets(string_array &ruleset_list, std::vector<ruleset_content> &ruleset_content_array);
|
||||
void refreshRulesets(RulesetConfigs &ruleset_list, std::vector<ruleset_content> &ruleset_content_array);
|
||||
|
||||
std::string parseProxy(const std::string &source)
|
||||
{
|
||||
@@ -222,7 +224,8 @@ std::string getRuleset(RESPONSE_CALLBACK_ARGS)
|
||||
for(std::string &x : vArray)
|
||||
x.insert(0, "ruleset,");
|
||||
std::vector<ruleset_content> rca;
|
||||
refreshRulesets(vArray, rca);
|
||||
RulesetConfigs confs = INIBinding::from<RulesetConfig>::from_ini(vArray);
|
||||
refreshRulesets(confs, rca);
|
||||
for(ruleset_content &x : rca)
|
||||
{
|
||||
std::string content = x.rule_content.get();
|
||||
@@ -256,8 +259,7 @@ std::string getRuleset(RESPONSE_CALLBACK_ARGS)
|
||||
if(strLine[pose - 1] == '\r')
|
||||
pose--;
|
||||
}
|
||||
else
|
||||
pose -= posb;
|
||||
pose -= posb;
|
||||
return 0;
|
||||
};
|
||||
|
||||
@@ -405,6 +407,50 @@ int importItems(string_array &target, bool scope_limit = true)
|
||||
return 0;
|
||||
}
|
||||
|
||||
toml::value parseToml(const std::string &content, const std::string &fname)
|
||||
{
|
||||
std::istringstream is(content);
|
||||
return toml::parse(is, fname);
|
||||
}
|
||||
|
||||
void importItems(std::vector<toml::value> &root, const std::string &import_key, bool scope_limit = true)
|
||||
{
|
||||
std::string content;
|
||||
std::vector<toml::value> newRoot;
|
||||
auto iter = root.begin();
|
||||
size_t count = 0;
|
||||
|
||||
std::string proxy = parseProxy(gProxyConfig);
|
||||
while(iter != root.end())
|
||||
{
|
||||
auto& table = iter->as_table();
|
||||
if(table.find("import") == table.end())
|
||||
newRoot.emplace_back(std::move(*iter));
|
||||
else
|
||||
{
|
||||
const std::string &path = toml::get<std::string>(table.at("import"));
|
||||
writeLog(0, "Trying to import items from " + path);
|
||||
if(fileExist(path))
|
||||
content = fileGet(path, scope_limit);
|
||||
else if(isLink(path))
|
||||
content = webGet(path, proxy, gCacheConfig);
|
||||
else
|
||||
writeLog(0, "File not found or not a valid URL: " + path, LOG_LEVEL_ERROR);
|
||||
if(content.size())
|
||||
{
|
||||
auto items = parseToml(content, path);
|
||||
auto list = toml::find<std::vector<toml::value>>(items, import_key);
|
||||
count += list.size();
|
||||
std::move(list.begin(), list.end(), std::back_inserter(newRoot));
|
||||
}
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
root.swap(newRoot);
|
||||
writeLog(0, "Imported " + std::to_string(count) + " item(s).");
|
||||
return;
|
||||
}
|
||||
|
||||
void readRegexMatch(YAML::Node node, const std::string &delimiter, string_array &dest, bool scope_limit = true)
|
||||
{
|
||||
YAML::Node object;
|
||||
@@ -488,8 +534,8 @@ void readGroup(YAML::Node node, string_array &dest, bool scope_limit = true)
|
||||
std::string url = "http://www.gstatic.com/generate_204", interval = "300", tolerance, timeout;
|
||||
object["name"] >>= name;
|
||||
object["type"] >>= type;
|
||||
tempArray.emplace_back("name=" + name);
|
||||
tempArray.emplace_back("type=" + type);
|
||||
tempArray.emplace_back(name);
|
||||
tempArray.emplace_back(type);
|
||||
object["url"] >>= url;
|
||||
object["interval"] >>= interval;
|
||||
object["tolerance"] >>= tolerance;
|
||||
@@ -509,13 +555,13 @@ void readGroup(YAML::Node node, string_array &dest, bool scope_limit = true)
|
||||
default:
|
||||
if(tempArray.size() < 3)
|
||||
continue;
|
||||
tempArray.emplace_back("url=" + url);
|
||||
tempArray.emplace_back("interval=" + interval + ",timeout=" + timeout + ",tolerance=" + tolerance);
|
||||
tempArray.emplace_back(url);
|
||||
tempArray.emplace_back(interval + "," + timeout + "," + tolerance);
|
||||
}
|
||||
|
||||
strLine = std::accumulate(std::next(tempArray.begin()), tempArray.end(), tempArray[0], [](std::string a, std::string b) -> std::string
|
||||
{
|
||||
return std::move(a) + "," + std::move(b);
|
||||
return std::move(a) + "`" + std::move(b);
|
||||
});
|
||||
dest.emplace_back(std::move(strLine));
|
||||
}
|
||||
@@ -555,7 +601,7 @@ void readRuleset(YAML::Node node, string_array &dest, bool scope_limit = true)
|
||||
importItems(dest, scope_limit);
|
||||
}
|
||||
|
||||
void refreshRulesets(string_array &ruleset_list, std::vector<ruleset_content> &ruleset_content_array)
|
||||
void refreshRulesets(RulesetConfigs &ruleset_list, std::vector<ruleset_content> &ruleset_content_array)
|
||||
{
|
||||
eraseElements(ruleset_content_array);
|
||||
std::string rule_group, rule_url, rule_url_typed, interval;
|
||||
@@ -563,26 +609,18 @@ void refreshRulesets(string_array &ruleset_list, std::vector<ruleset_content> &r
|
||||
|
||||
std::string proxy = parseProxy(gProxyRuleset);
|
||||
|
||||
for(std::string &x : ruleset_list)
|
||||
for(RulesetConfig &x : ruleset_list)
|
||||
{
|
||||
string_size pos = x.find(",");
|
||||
if(pos == x.npos || pos == x.size() - 1)
|
||||
continue;
|
||||
rule_group = trim(x.substr(0, pos));
|
||||
if(x.find("[]", pos + 1) == pos + 1)
|
||||
rule_group = x.Group;
|
||||
rule_url = x.Url;
|
||||
std::string::size_type pos = x.Url.find("[]");
|
||||
if(pos != std::string::npos)
|
||||
{
|
||||
rule_url = trim(x.substr(pos + 1));
|
||||
writeLog(0, "Adding rule '" + rule_url.substr(2) + "," + rule_group + "'.", LOG_LEVEL_INFO);
|
||||
rc = {rule_group, "", "", RULESET_SURGE, std::async(std::launch::async, [rule_url](){return rule_url;}), 0};
|
||||
writeLog(0, "Adding rule '" + rule_url.substr(pos + 2) + "," + rule_group + "'.", LOG_LEVEL_INFO);
|
||||
rc = {rule_group, "", "", RULESET_SURGE, std::async(std::launch::async, [=](){return rule_url.substr(pos);}), 0};
|
||||
}
|
||||
else
|
||||
{
|
||||
string_size pos2 = x.find(",", pos + 1);
|
||||
rule_url = trim(x.substr(pos + 1, pos2 - pos - 1));
|
||||
if(pos2 != x.npos)
|
||||
interval = x.substr(pos2 + 1);
|
||||
else
|
||||
interval.clear();
|
||||
ruleset_type type = RULESET_SURGE;
|
||||
rule_url_typed = rule_url;
|
||||
auto iter = std::find_if(RulesetTypes.begin(), RulesetTypes.end(), [rule_url](auto y){ return startsWith(rule_url, y.first); });
|
||||
@@ -592,7 +630,7 @@ void refreshRulesets(string_array &ruleset_list, std::vector<ruleset_content> &r
|
||||
type = iter->second;
|
||||
}
|
||||
writeLog(0, "Updating ruleset url '" + rule_url + "' with group '" + rule_group + "'.", LOG_LEVEL_INFO);
|
||||
rc = {rule_group, rule_url, rule_url_typed, type, fetchFileAsync(rule_url, proxy, gCacheRuleset, gAsyncFetchRuleset), to_int(interval, 0)};
|
||||
rc = {rule_group, rule_url, rule_url_typed, type, fetchFileAsync(rule_url, proxy, gCacheRuleset, gAsyncFetchRuleset), x.Interval};
|
||||
}
|
||||
ruleset_content_array.emplace_back(std::move(rc));
|
||||
}
|
||||
@@ -662,13 +700,15 @@ void readYAMLConf(YAML::Node &node)
|
||||
if(section["stream_rule"].IsSequence())
|
||||
{
|
||||
readRegexMatch(section["stream_rule"], "|", tempArray, false);
|
||||
safe_set_streams(tempArray);
|
||||
auto configs = INIBinding::from<RegexMatchConfig>::from_ini(tempArray, "|");
|
||||
safe_set_streams(configs);
|
||||
eraseElements(tempArray);
|
||||
}
|
||||
if(section["time_rule"].IsSequence())
|
||||
{
|
||||
readRegexMatch(section["time_rule"], "|", tempArray, false);
|
||||
safe_set_times(tempArray);
|
||||
auto configs = INIBinding::from<RegexMatchConfig>::from_ini(tempArray, "|");
|
||||
safe_set_times(configs);
|
||||
eraseElements(tempArray);
|
||||
}
|
||||
}
|
||||
@@ -696,7 +736,8 @@ void readYAMLConf(YAML::Node &node)
|
||||
if(section["rename_node"].IsSequence())
|
||||
{
|
||||
readRegexMatch(section["rename_node"], "@", tempArray, false);
|
||||
safe_set_renames(tempArray);
|
||||
auto configs = INIBinding::from<RegexMatchConfig>::from_ini(tempArray, "@");
|
||||
safe_set_renames(configs);
|
||||
eraseElements(tempArray);
|
||||
}
|
||||
|
||||
@@ -724,7 +765,8 @@ void readYAMLConf(YAML::Node &node)
|
||||
if(section["rules"].IsSequence())
|
||||
{
|
||||
readEmoji(section["rules"], tempArray, false);
|
||||
safe_set_emojis(tempArray);
|
||||
auto configs = INIBinding::from<RegexMatchConfig>::from_ini(tempArray, ",");
|
||||
safe_set_emojis(configs);
|
||||
eraseElements(tempArray);
|
||||
}
|
||||
}
|
||||
@@ -746,12 +788,20 @@ void readYAMLConf(YAML::Node &node)
|
||||
}
|
||||
const char *ruleset_title = section["rulesets"].IsDefined() ? "rulesets" : "surge_ruleset";
|
||||
if(section[ruleset_title].IsSequence())
|
||||
readRuleset(section[ruleset_title], gCustomRulesets, false);
|
||||
{
|
||||
string_array vArray;
|
||||
readRuleset(section[ruleset_title], vArray, false);
|
||||
gCustomRulesets = INIBinding::from<RulesetConfig>::from_ini(vArray);
|
||||
}
|
||||
}
|
||||
|
||||
const char *groups_title = node["proxy_groups"].IsDefined() ? "proxy_groups" : "proxy_group";
|
||||
if(node[groups_title].IsDefined() && node[groups_title]["custom_proxy_group"].IsDefined())
|
||||
readGroup(node[groups_title]["custom_proxy_group"], gCustomProxyGroups, false);
|
||||
{
|
||||
string_array vArray;
|
||||
readGroup(node[groups_title]["custom_proxy_group"], vArray, false);
|
||||
gCustomProxyGroups = INIBinding::from<ProxyGroupConfig>::from_ini(vArray);
|
||||
}
|
||||
|
||||
if(node["template"].IsDefined())
|
||||
{
|
||||
@@ -771,26 +821,26 @@ void readYAMLConf(YAML::Node &node)
|
||||
|
||||
if(node["aliases"].IsSequence())
|
||||
{
|
||||
reset_redirect();
|
||||
webServer.reset_redirect();
|
||||
for(size_t i = 0; i < node["aliases"].size(); i++)
|
||||
{
|
||||
std::string uri, target;
|
||||
node["aliases"][i]["uri"] >> uri;
|
||||
node["aliases"][i]["target"] >> target;
|
||||
append_redirect(uri, target);
|
||||
webServer.append_redirect(uri, target);
|
||||
}
|
||||
}
|
||||
|
||||
if(node["tasks"].IsSequence())
|
||||
{
|
||||
gCronTasks.clear();
|
||||
string_array vArray;
|
||||
for(size_t i = 0; i < node["tasks"].size(); i++)
|
||||
{
|
||||
std::string name, exp, path, timeout;
|
||||
node["tasks"][i]["import"] >> name;
|
||||
if(name.size())
|
||||
{
|
||||
gCronTasks.emplace_back("!!import:" + name);
|
||||
vArray.emplace_back("!!import:" + name);
|
||||
continue;
|
||||
}
|
||||
node["tasks"][i]["name"] >> name;
|
||||
@@ -798,10 +848,11 @@ void readYAMLConf(YAML::Node &node)
|
||||
node["tasks"][i]["path"] >> path;
|
||||
node["tasks"][i]["timeout"] >> timeout;
|
||||
strLine = name + "`" + exp + "`" + path + "`" + timeout;
|
||||
gCronTasks.push_back(std::move(strLine));
|
||||
vArray.emplace_back(std::move(strLine));
|
||||
}
|
||||
importItems(gCronTasks, false);
|
||||
gEnableCron = !gCronTasks.empty();
|
||||
importItems(vArray, false);
|
||||
gEnableCron = !vArray.empty();
|
||||
gCronTasks = INIBinding::from<CronTaskConfig>::from_ini(vArray);
|
||||
refresh_schedule();
|
||||
}
|
||||
|
||||
@@ -809,8 +860,8 @@ void readYAMLConf(YAML::Node &node)
|
||||
{
|
||||
node["server"]["listen"] >> gListenAddress;
|
||||
node["server"]["port"] >> gListenPort;
|
||||
node["server"]["serve_file_root"] >>= gServeFileRoot;
|
||||
gServeFile = !gServeFileRoot.empty();
|
||||
node["server"]["serve_file_root"] >>= webServer.serve_file_root;
|
||||
webServer.serve_file = !webServer.serve_file_root.empty();
|
||||
}
|
||||
|
||||
if(node["advanced"].IsDefined())
|
||||
@@ -866,6 +917,224 @@ void readYAMLConf(YAML::Node &node)
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, class... U>
|
||||
void find_if_exist(const toml::value &v, const toml::key &k, T& target, U&&... args)
|
||||
{
|
||||
if(v.contains(k)) target = toml::find<T>(v, k);
|
||||
if constexpr (sizeof...(args)) find_if_exist(v, std::forward<U>(args)...);
|
||||
}
|
||||
|
||||
std::string join(const string_array &arr, const std::string &delimiter = "|")
|
||||
{
|
||||
if(arr.size() == 0)
|
||||
return "";
|
||||
if(arr.size() == 1)
|
||||
return arr[0];
|
||||
return std::accumulate(arr.begin() + 1, arr.end(), arr[0], [&](const std::string &a, const std::string &b) { return a + delimiter + b; });
|
||||
}
|
||||
|
||||
void operate_toml_kv_table(const std::vector<toml::table> &arr, const toml::key &key_name, const toml::key &value_name, std::function<void (const toml::value&, const toml::value&)> binary_op)
|
||||
{
|
||||
for(const toml::table &table : arr)
|
||||
{
|
||||
const auto &key = table.at(key_name), value = table.at(value_name);
|
||||
binary_op(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
void readTOMLConf(toml::value &root)
|
||||
{
|
||||
const auto §ion_common = toml::find(root, "common");
|
||||
string_array default_url, insert_url;
|
||||
|
||||
find_if_exist(section_common, "default_url", default_url, "insert_url", insert_url);
|
||||
gDefaultUrls = join(default_url);
|
||||
gInsertUrls = join(insert_url);
|
||||
|
||||
bool filter = false;
|
||||
find_if_exist(section_common,
|
||||
"api_mode", gAPIMode,
|
||||
"api_access_token", gAccessToken,
|
||||
"exclude_remarks", gExcludeRemarks,
|
||||
"include_remarks", gIncludeRemarks,
|
||||
"enable_insert", gEnableInsert,
|
||||
"prepend_insert_url", gPrependInsert,
|
||||
"enable_filter", filter,
|
||||
"default_external_config", gDefaultExtConfig,
|
||||
"base_path", gBasePath,
|
||||
"clash_rule_base", gClashBase,
|
||||
"surge_rule_base", gSurgeBase,
|
||||
"surfboard_rule_base", gSurfboardBase,
|
||||
"mellow_rule_base", gMellowBase,
|
||||
"quan_rule_base", gQuanBase,
|
||||
"quanx_rule_base", gQuanXBase,
|
||||
"loon_rule_base", gLoonBase,
|
||||
"proxy_config", gProxyConfig,
|
||||
"proxy_ruleset", gProxyRuleset,
|
||||
"proxy_subscription", gProxySubscription,
|
||||
"append_proxy_type", gAppendType
|
||||
);
|
||||
|
||||
if(filter)
|
||||
find_if_exist(section_common, "filter_script", gFilterScript);
|
||||
else
|
||||
gFilterScript.clear();
|
||||
|
||||
safe_set_streams(toml::find_or<RegexMatchConfigs>(root, "userinfo", "stream_rule", RegexMatchConfigs{}));
|
||||
safe_set_times(toml::find_or<RegexMatchConfigs>(root, "userinfo", "time_rule", RegexMatchConfigs{}));
|
||||
|
||||
const auto §ion_node_pref = toml::find(root, "node_pref");
|
||||
|
||||
find_if_exist(section_node_pref,
|
||||
"udp_flag", gUDP,
|
||||
"tcp_fast_open_flag", gTFO,
|
||||
"skip_cert_verify_flag", gSkipCertVerify,
|
||||
"tls13_flag", gTLS13,
|
||||
"sort_flag", gEnableSort,
|
||||
"sort_script", gSortScript,
|
||||
"filter_deprecated_nodes", gFilterDeprecated,
|
||||
"append_sub_userinfo", gAppendUserinfo,
|
||||
"clash_use_new_field_name", gClashUseNewField,
|
||||
"clash_proxies_style", gClashProxiesStyle
|
||||
);
|
||||
|
||||
auto renameconfs = toml::find_or<std::vector<toml::value>>(section_node_pref, "rename_node", {});
|
||||
importItems(renameconfs, "rename_node", false);
|
||||
safe_set_renames(toml::get<RegexMatchConfigs>(toml::value(renameconfs)));
|
||||
|
||||
const auto §ion_managed = toml::find(root, "managed_config");
|
||||
|
||||
find_if_exist(section_managed,
|
||||
"write_managed_config", gWriteManagedConfig,
|
||||
"managed_config_prefix", gManagedConfigPrefix,
|
||||
"config_update_interval", gUpdateInterval,
|
||||
"config_update_strict", gUpdateStrict,
|
||||
"quanx_device_id", gQuanXDevID
|
||||
);
|
||||
|
||||
const auto §ion_surge_external = toml::find(root, "surge_external_proxy");
|
||||
find_if_exist(section_surge_external,
|
||||
"surge_ssr_path", gSurgeSSRPath,
|
||||
"resolve_hostname", gSurgeResolveHostname
|
||||
);
|
||||
|
||||
const auto §ion_emojis = toml::find(root, "emojis");
|
||||
|
||||
find_if_exist(section_emojis,
|
||||
"add_emoji", gAddEmoji,
|
||||
"remove_old_emoji", gRemoveEmoji
|
||||
);
|
||||
|
||||
auto emojiconfs = toml::find_or<std::vector<toml::value>>(section_emojis, "emoji", {});
|
||||
importItems(emojiconfs, "emoji", false);
|
||||
safe_set_emojis(toml::get<RegexMatchConfigs>(toml::value(emojiconfs)));
|
||||
|
||||
auto groups = toml::find_or<std::vector<toml::value>>(root, "custom_groups", {});
|
||||
importItems(groups, "custom_groups", false);
|
||||
gCustomProxyGroups = toml::get<ProxyGroupConfigs>(toml::value(groups));
|
||||
|
||||
const auto §ion_ruleset = toml::find(root, "ruleset");
|
||||
|
||||
find_if_exist(section_ruleset,
|
||||
"enabled", gEnableRuleGen,
|
||||
"overwrite_original_rules", gOverwriteOriginalRules,
|
||||
"update_ruleset_on_request", gUpdateRulesetOnRequest
|
||||
);
|
||||
|
||||
auto rulesets = toml::find_or<std::vector<toml::value>>(root, "rulesets", {});
|
||||
importItems(rulesets, "rulesets", false);
|
||||
gCustomRulesets = toml::get<RulesetConfigs>(toml::value(rulesets));
|
||||
|
||||
const auto §ion_template = toml::find(root, "template");
|
||||
|
||||
gTemplatePath = toml::find_or(section_template, "template_path", "template");
|
||||
|
||||
eraseElements(gTemplateVars);
|
||||
operate_toml_kv_table(toml::find_or<std::vector<toml::table>>(section_template, "globals", {}), "key", "value", [&](const toml::value &key, const toml::value &value)
|
||||
{
|
||||
gTemplateVars[key.as_string()] = value.as_string();
|
||||
});
|
||||
|
||||
webServer.reset_redirect();
|
||||
operate_toml_kv_table(toml::find_or<std::vector<toml::table>>(root, "aliases", {}), "uri", "target", [&](const toml::value &key, const toml::value &value)
|
||||
{
|
||||
webServer.append_redirect(key.as_string(), value.as_string());
|
||||
});
|
||||
|
||||
auto tasks = toml::find_or<std::vector<toml::value>>(root, "tasks", {});
|
||||
importItems(tasks, "tasks", false);
|
||||
gCronTasks = toml::get<CronTaskConfigs>(toml::value(tasks));
|
||||
|
||||
const auto §ion_server = toml::find(root, "server");
|
||||
|
||||
find_if_exist(section_server,
|
||||
"listen", gListenAddress,
|
||||
"port", gListenPort,
|
||||
"serve_file_root", webServer.serve_file_root
|
||||
);
|
||||
webServer.serve_file = !webServer.serve_file_root.empty();
|
||||
|
||||
const auto §ion_advanced = toml::find(root, "advanced");
|
||||
|
||||
std::string log_level;
|
||||
bool enable_cache = true;
|
||||
int cache_subscription = gCacheSubscription, cache_config = gCacheConfig, cache_ruleset = gCacheRuleset;
|
||||
|
||||
find_if_exist(section_advanced,
|
||||
"log_level", log_level,
|
||||
"print_debug_info", gPrintDbgInfo,
|
||||
"max_pending_connections", gMaxPendingConns,
|
||||
"max_concurrent_threads", gMaxConcurThreads,
|
||||
"max_allowed_rulesets", gMaxAllowedRulesets,
|
||||
"max_allowed_rules", gMaxAllowedRules,
|
||||
"max_allowed_download_size", gMaxAllowedDownloadSize,
|
||||
"enable_cache", enable_cache,
|
||||
"cache_subscription", cache_subscription,
|
||||
"cache_config", cache_config,
|
||||
"cache_ruleset", cache_ruleset,
|
||||
"script_clean_context", gScriptCleanContext,
|
||||
"async_fetch_ruleset", gAsyncFetchRuleset,
|
||||
"skip_failed_links", gSkipFailedLinks
|
||||
);
|
||||
|
||||
if(gPrintDbgInfo)
|
||||
gLogLevel = LOG_LEVEL_VERBOSE;
|
||||
else
|
||||
{
|
||||
switch(hash_(log_level))
|
||||
{
|
||||
case "warn"_hash:
|
||||
gLogLevel = LOG_LEVEL_WARNING;
|
||||
break;
|
||||
case "error"_hash:
|
||||
gLogLevel = LOG_LEVEL_ERROR;
|
||||
break;
|
||||
case "fatal"_hash:
|
||||
gLogLevel = LOG_LEVEL_FATAL;
|
||||
break;
|
||||
case "verbose"_hash:
|
||||
gLogLevel = LOG_LEVEL_VERBOSE;
|
||||
break;
|
||||
case "debug"_hash:
|
||||
gLogLevel = LOG_LEVEL_DEBUG;
|
||||
break;
|
||||
default:
|
||||
gLogLevel = LOG_LEVEL_INFO;
|
||||
}
|
||||
}
|
||||
|
||||
if(enable_cache)
|
||||
{
|
||||
gCacheSubscription = cache_subscription;
|
||||
gCacheConfig = cache_config;
|
||||
gCacheRuleset = cache_ruleset;
|
||||
}
|
||||
else
|
||||
{
|
||||
gCacheSubscription = gCacheConfig = gCacheRuleset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void readConf()
|
||||
{
|
||||
guarded_mutex guard(gMutexConfigure);
|
||||
@@ -886,10 +1155,18 @@ void readConf()
|
||||
if(yaml.size() && yaml["common"])
|
||||
return readYAMLConf(yaml);
|
||||
}
|
||||
toml::value conf = parseToml(prefdata, gPrefPath);
|
||||
if(!conf.is_uninitialized() && toml::find_or<int>(conf, "version", 0))
|
||||
return readTOMLConf(conf);
|
||||
}
|
||||
catch (YAML::Exception &e)
|
||||
{
|
||||
//ignore
|
||||
//ignore yaml parse error
|
||||
}
|
||||
catch (toml::exception &e)
|
||||
{
|
||||
//ignore toml parse error
|
||||
writeLog(0, e.what(), LOG_LEVEL_DEBUG);
|
||||
}
|
||||
|
||||
INIReader ini;
|
||||
@@ -960,7 +1237,8 @@ void readConf()
|
||||
{
|
||||
ini.GetAll("rename_node", tempArray);
|
||||
importItems(tempArray, false);
|
||||
safe_set_renames(tempArray);
|
||||
auto configs = INIBinding::from<RegexMatchConfig>::from_ini(tempArray, "@");
|
||||
safe_set_renames(configs);
|
||||
eraseElements(tempArray);
|
||||
}
|
||||
}
|
||||
@@ -972,14 +1250,16 @@ void readConf()
|
||||
{
|
||||
ini.GetAll("stream_rule", tempArray);
|
||||
importItems(tempArray, false);
|
||||
safe_set_streams(tempArray);
|
||||
auto configs = INIBinding::from<RegexMatchConfig>::from_ini(tempArray, "|");
|
||||
safe_set_streams(configs);
|
||||
eraseElements(tempArray);
|
||||
}
|
||||
if(ini.ItemPrefixExist("time_rule"))
|
||||
{
|
||||
ini.GetAll("time_rule", tempArray);
|
||||
importItems(tempArray, false);
|
||||
safe_set_times(tempArray);
|
||||
auto configs = INIBinding::from<RegexMatchConfig>::from_ini(tempArray, "|");
|
||||
safe_set_times(configs);
|
||||
eraseElements(tempArray);
|
||||
}
|
||||
}
|
||||
@@ -998,7 +1278,8 @@ void readConf()
|
||||
{
|
||||
ini.GetAll("rule", tempArray);
|
||||
importItems(tempArray, false);
|
||||
safe_set_emojis(tempArray);
|
||||
auto configs = INIBinding::from<RegexMatchConfig>::from_ini(tempArray, ",");
|
||||
safe_set_emojis(configs);
|
||||
eraseElements(tempArray);
|
||||
}
|
||||
|
||||
@@ -1013,13 +1294,17 @@ void readConf()
|
||||
ini.GetBoolIfExist("update_ruleset_on_request", gUpdateRulesetOnRequest);
|
||||
if(ini.ItemPrefixExist("ruleset"))
|
||||
{
|
||||
ini.GetAll("ruleset", gCustomRulesets);
|
||||
importItems(gCustomRulesets, true);
|
||||
string_array vArray;
|
||||
ini.GetAll("ruleset", vArray);
|
||||
importItems(vArray, false);
|
||||
gCustomRulesets = INIBinding::from<RulesetConfig>::from_ini(vArray);
|
||||
}
|
||||
else if(ini.ItemPrefixExist("surge_ruleset"))
|
||||
{
|
||||
ini.GetAll("surge_ruleset", gCustomRulesets);
|
||||
importItems(gCustomRulesets, false);
|
||||
string_array vArray;
|
||||
ini.GetAll("surge_ruleset", vArray);
|
||||
importItems(vArray, false);
|
||||
gCustomRulesets = INIBinding::from<RulesetConfig>::from_ini(vArray);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1034,8 +1319,10 @@ void readConf()
|
||||
ini.EnterSection("clash_proxy_group");
|
||||
if(ini.ItemPrefixExist("custom_proxy_group"))
|
||||
{
|
||||
ini.GetAll("custom_proxy_group", gCustomProxyGroups);
|
||||
importItems(gCustomProxyGroups, false);
|
||||
string_array vArray;
|
||||
ini.GetAll("custom_proxy_group", vArray);
|
||||
importItems(vArray, false);
|
||||
gCustomProxyGroups = INIBinding::from<ProxyGroupConfig>::from_ini(vArray);
|
||||
}
|
||||
|
||||
ini.EnterSection("template");
|
||||
@@ -1055,26 +1342,27 @@ void readConf()
|
||||
{
|
||||
ini.EnterSection("aliases");
|
||||
ini.GetItems(tempmap);
|
||||
reset_redirect();
|
||||
webServer.reset_redirect();
|
||||
for(auto &x : tempmap)
|
||||
append_redirect(x.first, x.second);
|
||||
webServer.append_redirect(x.first, x.second);
|
||||
}
|
||||
|
||||
if(ini.SectionExist("tasks"))
|
||||
{
|
||||
gCronTasks.clear();
|
||||
string_array vArray;
|
||||
ini.EnterSection("tasks");
|
||||
ini.GetAll("task", gCronTasks);
|
||||
importItems(gCronTasks, false);
|
||||
gEnableCron = !gCronTasks.empty();
|
||||
ini.GetAll("task", vArray);
|
||||
importItems(vArray, false);
|
||||
gEnableCron = !vArray.empty();
|
||||
gCronTasks = INIBinding::from<CronTaskConfig>::from_ini(vArray);
|
||||
refresh_schedule();
|
||||
}
|
||||
|
||||
ini.EnterSection("server");
|
||||
ini.GetIfExist("listen", gListenAddress);
|
||||
ini.GetIntIfExist("port", gListenPort);
|
||||
gServeFileRoot = ini.Get("serve_file_root");
|
||||
gServeFile = !gServeFileRoot.empty();
|
||||
webServer.serve_file_root = ini.Get("serve_file_root");
|
||||
webServer.serve_file = !webServer.serve_file_root.empty();
|
||||
|
||||
ini.EnterSection("advanced");
|
||||
std::string log_level;
|
||||
@@ -1135,8 +1423,8 @@ void readConf()
|
||||
|
||||
struct ExternalConfig
|
||||
{
|
||||
string_array custom_proxy_group;
|
||||
string_array surge_ruleset;
|
||||
ProxyGroupConfigs custom_proxy_group;
|
||||
RulesetConfigs surge_ruleset;
|
||||
std::string clash_rule_base;
|
||||
std::string surge_rule_base;
|
||||
std::string surfboard_rule_base;
|
||||
@@ -1145,8 +1433,8 @@ struct ExternalConfig
|
||||
std::string quanx_rule_base;
|
||||
std::string loon_rule_base;
|
||||
std::string sssub_rule_base;
|
||||
string_array rename;
|
||||
string_array emoji;
|
||||
RegexMatchConfigs rename;
|
||||
RegexMatchConfigs emoji;
|
||||
string_array include;
|
||||
string_array exclude;
|
||||
template_args *tpl_args = NULL;
|
||||
@@ -1176,28 +1464,41 @@ int loadExternalYAML(YAML::Node &node, ExternalConfig &ext)
|
||||
|
||||
const char *group_name = section["proxy_groups"].IsDefined() ? "proxy_groups" : "custom_proxy_group";
|
||||
if(section[group_name].size())
|
||||
readGroup(section[group_name], ext.custom_proxy_group, gAPIMode);
|
||||
{
|
||||
string_array vArray;
|
||||
readGroup(section[group_name], vArray, gAPIMode);
|
||||
ext.custom_proxy_group = INIBinding::from<ProxyGroupConfig>::from_ini(vArray);
|
||||
}
|
||||
|
||||
const char *ruleset_name = section["rulesets"].IsDefined() ? "rulesets" : "surge_ruleset";
|
||||
if(section[ruleset_name].size())
|
||||
{
|
||||
readRuleset(section[ruleset_name], ext.surge_ruleset, gAPIMode);
|
||||
if(gMaxAllowedRulesets && ext.surge_ruleset.size() > gMaxAllowedRulesets)
|
||||
string_array vArray;
|
||||
readRuleset(section[ruleset_name], vArray, gAPIMode);
|
||||
if(gMaxAllowedRulesets && vArray.size() > gMaxAllowedRulesets)
|
||||
{
|
||||
writeLog(0, "Ruleset count in external config has exceeded limit.", LOG_LEVEL_WARNING);
|
||||
eraseElements(ext.surge_ruleset);
|
||||
return -1;
|
||||
}
|
||||
ext.surge_ruleset = INIBinding::from<RulesetConfig>::from_ini(vArray);
|
||||
}
|
||||
|
||||
if(section["rename_node"].size())
|
||||
readRegexMatch(section["rename_node"], "@", ext.rename, gAPIMode);
|
||||
{
|
||||
string_array vArray;
|
||||
readRegexMatch(section["rename_node"], "@", vArray, gAPIMode);
|
||||
ext.rename = INIBinding::from<RegexMatchConfig>::from_ini(vArray, "@");
|
||||
}
|
||||
|
||||
ext.add_emoji = safe_as<std::string>(section["add_emoji"]);
|
||||
ext.remove_old_emoji = safe_as<std::string>(section["remove_old_emoji"]);
|
||||
const char *emoji_name = section["emojis"].IsDefined() ? "emojis" : "emoji";
|
||||
if(section[emoji_name].size())
|
||||
readEmoji(section[emoji_name], ext.emoji, gAPIMode);
|
||||
{
|
||||
string_array vArray;
|
||||
readEmoji(section[emoji_name], vArray, gAPIMode);
|
||||
ext.emoji = INIBinding::from<RegexMatchConfig>::from_ini(vArray, ",");
|
||||
}
|
||||
|
||||
section["include_remarks"] >> ext.include;
|
||||
section["exclude_remarks"] >> ext.exclude;
|
||||
@@ -1216,6 +1517,57 @@ int loadExternalYAML(YAML::Node &node, ExternalConfig &ext)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int loadExternalTOML(toml::value &root, ExternalConfig &ext)
|
||||
{
|
||||
const auto §ion = toml::find(root, "custom");
|
||||
|
||||
find_if_exist(section,
|
||||
"enable_rule_generator", ext.enable_rule_generator,
|
||||
"overwrite_original_rules", ext.overwrite_original_rules,
|
||||
"clash_rule_base", ext.clash_rule_base,
|
||||
"surge_rule_base", ext.surge_ruleset,
|
||||
"surfboard_rule_base", ext.surfboard_rule_base,
|
||||
"mellow_rule_base", ext.mellow_rule_base,
|
||||
"quan_rule_base", ext.quan_rule_base,
|
||||
"quanx_rule_base", ext.quanx_rule_base,
|
||||
"sssub_rule_base", ext.sssub_rule_base,
|
||||
"add_emoji", ext.add_emoji,
|
||||
"remove_old_emoji", ext.remove_old_emoji,
|
||||
"include_remarks", ext.include,
|
||||
"exclude_remarks", ext.exclude
|
||||
);
|
||||
|
||||
if(ext.tpl_args != nullptr) operate_toml_kv_table(toml::find_or<std::vector<toml::table>>(section, "template_args", {}), "key", "value",
|
||||
[&](const toml::value &key, const toml::value &value)
|
||||
{
|
||||
std::string val = toml::format(value);
|
||||
ext.tpl_args->local_vars[key.as_string()] = val;
|
||||
});
|
||||
|
||||
auto groups = toml::find_or<std::vector<toml::value>>(root, "custom_groups", {});
|
||||
importItems(groups, "custom_groups", false);
|
||||
ext.custom_proxy_group = toml::get<ProxyGroupConfigs>(toml::value(groups));
|
||||
|
||||
auto rulesets = toml::find_or<std::vector<toml::value>>(root, "rulesets", {});
|
||||
importItems(rulesets, "rulesets", false);
|
||||
if(gMaxAllowedRulesets && rulesets.size() > gMaxAllowedRulesets)
|
||||
{
|
||||
writeLog(0, "Ruleset count in external config has exceeded limit. ", LOG_LEVEL_WARNING);
|
||||
return -1;
|
||||
}
|
||||
ext.surge_ruleset = toml::get<RulesetConfigs>(toml::value(rulesets));
|
||||
|
||||
auto emojiconfs = toml::find_or<std::vector<toml::value>>(root, "emoji", {});
|
||||
importItems(emojiconfs, "emoji", false);
|
||||
ext.emoji = toml::get<RegexMatchConfigs>(toml::value(emojiconfs));
|
||||
|
||||
auto renameconfs = toml::find_or<std::vector<toml::value>>(root, "rename_node", {});
|
||||
importItems(renameconfs, "rename_node", false);
|
||||
ext.rename = toml::get<RegexMatchConfigs>(toml::value(renameconfs));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int loadExternalConfig(std::string &path, ExternalConfig &ext)
|
||||
{
|
||||
std::string base_content, proxy = parseProxy(gProxyConfig), config = fetchFile(path, proxy, gCacheConfig);
|
||||
@@ -1227,11 +1579,18 @@ int loadExternalConfig(std::string &path, ExternalConfig &ext)
|
||||
YAML::Node yaml = YAML::Load(base_content);
|
||||
if(yaml.size() && yaml["custom"].IsDefined())
|
||||
return loadExternalYAML(yaml, ext);
|
||||
toml::value conf = parseToml(base_content, path);
|
||||
if(!conf.is_uninitialized() && toml::find_or<int>(conf, "version", 0))
|
||||
return loadExternalTOML(conf, ext);
|
||||
}
|
||||
catch (YAML::Exception &e)
|
||||
{
|
||||
//ignore
|
||||
}
|
||||
catch (toml::exception &e)
|
||||
{
|
||||
//ignore
|
||||
}
|
||||
|
||||
INIReader ini;
|
||||
ini.store_isolated_line = true;
|
||||
@@ -1246,20 +1605,23 @@ int loadExternalConfig(std::string &path, ExternalConfig &ext)
|
||||
ini.EnterSection("custom");
|
||||
if(ini.ItemPrefixExist("custom_proxy_group"))
|
||||
{
|
||||
ini.GetAll("custom_proxy_group", ext.custom_proxy_group);
|
||||
importItems(ext.custom_proxy_group, gAPIMode);
|
||||
string_array vArray;
|
||||
ini.GetAll("custom_proxy_group", vArray);
|
||||
importItems(vArray, gAPIMode);
|
||||
ext.custom_proxy_group = INIBinding::from<ProxyGroupConfig>::from_ini(vArray);
|
||||
}
|
||||
std::string ruleset_name = ini.ItemPrefixExist("ruleset") ? "ruleset" : "surge_ruleset";
|
||||
if(ini.ItemPrefixExist(ruleset_name))
|
||||
{
|
||||
ini.GetAll(ruleset_name, ext.surge_ruleset);
|
||||
importItems(ext.surge_ruleset, gAPIMode);
|
||||
if(gMaxAllowedRulesets && ext.surge_ruleset.size() > gMaxAllowedRulesets)
|
||||
string_array vArray;
|
||||
ini.GetAll(ruleset_name, vArray);
|
||||
importItems(vArray, gAPIMode);
|
||||
if(gMaxAllowedRulesets && vArray.size() > gMaxAllowedRulesets)
|
||||
{
|
||||
writeLog(0, "Ruleset count in external config has exceeded limit. ", LOG_LEVEL_WARNING);
|
||||
eraseElements(ext.surge_ruleset);
|
||||
return -1;
|
||||
}
|
||||
ext.surge_ruleset = INIBinding::from<RulesetConfig>::from_ini(vArray);
|
||||
}
|
||||
|
||||
ini.GetIfExist("clash_rule_base", ext.clash_rule_base);
|
||||
@@ -1276,22 +1638,26 @@ int loadExternalConfig(std::string &path, ExternalConfig &ext)
|
||||
|
||||
if(ini.ItemPrefixExist("rename"))
|
||||
{
|
||||
ini.GetAll("rename", ext.rename);
|
||||
importItems(ext.rename, gAPIMode);
|
||||
string_array vArray;
|
||||
ini.GetAll("rename", vArray);
|
||||
importItems(vArray, gAPIMode);
|
||||
ext.rename = INIBinding::from<RegexMatchConfig>::from_ini(vArray, "@");
|
||||
}
|
||||
ext.add_emoji = ini.Get("add_emoji");
|
||||
ext.remove_old_emoji = ini.Get("remove_old_emoji");
|
||||
if(ini.ItemPrefixExist("emoji"))
|
||||
{
|
||||
ini.GetAll("emoji", ext.emoji);
|
||||
importItems(ext.emoji, gAPIMode);
|
||||
string_array vArray;
|
||||
ini.GetAll("emoji", vArray);
|
||||
importItems(vArray, gAPIMode);
|
||||
ext.emoji = INIBinding::from<RegexMatchConfig>::from_ini(vArray, ",");
|
||||
}
|
||||
if(ini.ItemPrefixExist("include_remarks"))
|
||||
ini.GetAll("include_remarks", ext.include);
|
||||
if(ini.ItemPrefixExist("exclude_remarks"))
|
||||
ini.GetAll("exclude_remarks", ext.exclude);
|
||||
|
||||
if(ini.SectionExist("template") && ext.tpl_args != NULL)
|
||||
if(ini.SectionExist("template") && ext.tpl_args != nullptr)
|
||||
{
|
||||
ini.EnterSection("template");
|
||||
string_multimap tempmap;
|
||||
@@ -1354,7 +1720,9 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
tribool argPrependInsert = getUrlArg(argument, "prepend"), argGenClassicalRuleProvider = getUrlArg(argument, "classic"), argTLS13 = getUrlArg(argument, "tls13");
|
||||
|
||||
std::string base_content, output_content;
|
||||
string_array lCustomProxyGroups = gCustomProxyGroups, lCustomRulesets = gCustomRulesets, lIncludeRemarks = gIncludeRemarks, lExcludeRemarks = gExcludeRemarks;
|
||||
ProxyGroupConfigs lCustomProxyGroups = gCustomProxyGroups;
|
||||
RulesetConfigs lCustomRulesets = gCustomRulesets;
|
||||
string_array lIncludeRemarks = gIncludeRemarks, lExcludeRemarks = gExcludeRemarks;
|
||||
std::vector<ruleset_content> lRulesetContent;
|
||||
extra_settings ext;
|
||||
std::string subInfo, dummy;
|
||||
@@ -1488,11 +1856,17 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
{
|
||||
/// loading custom groups
|
||||
if(argCustomGroups.size() && !ext.nodelist)
|
||||
lCustomProxyGroups = split(argCustomGroups, "@");
|
||||
{
|
||||
string_array vArray = split(argCustomGroups, "@");
|
||||
lCustomProxyGroups = INIBinding::from<ProxyGroupConfig>::from_ini(vArray);
|
||||
}
|
||||
|
||||
/// loading custom rulesets
|
||||
if(argCustomRulesets.size() && !ext.nodelist)
|
||||
lCustomRulesets = split(argCustomRulesets, "@");
|
||||
{
|
||||
string_array vArray = split(argCustomRulesets, "@");
|
||||
lCustomRulesets = INIBinding::from<RulesetConfig>::from_ini(vArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ext.enable_rule_generator && !ext.nodelist && !lSimpleSubscription)
|
||||
@@ -1517,7 +1891,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
if(ext.add_emoji && ext.emoji_array.empty())
|
||||
ext.emoji_array = safe_get_emojis();
|
||||
if(argRenames.size())
|
||||
ext.rename_array = split(argRenames, "`");
|
||||
ext.rename_array = INIBinding::from<RegexMatchConfig>::from_ini(split(argRenames, "`"), "@");
|
||||
else if(ext.rename_array.empty())
|
||||
ext.rename_array = safe_get_renames();
|
||||
|
||||
@@ -1537,7 +1911,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
}
|
||||
|
||||
//start parsing urls
|
||||
string_array stream_temp = safe_get_streams(), time_temp = safe_get_times();
|
||||
RegexMatchConfigs stream_temp = safe_get_streams(), time_temp = safe_get_times();
|
||||
|
||||
//loading urls
|
||||
string_array urls;
|
||||
@@ -1645,7 +2019,8 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
}
|
||||
}
|
||||
*/
|
||||
script_safe_runner(ext.js_runtime, ext.js_context, [&](qjs::Context &ctx){
|
||||
script_safe_runner(ext.js_runtime, ext.js_context, [&](qjs::Context &ctx)
|
||||
{
|
||||
try
|
||||
{
|
||||
ctx.eval(filterScript);
|
||||
@@ -1684,7 +2059,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
}
|
||||
*/
|
||||
|
||||
string_array dummy_group;
|
||||
ProxyGroupConfigs dummy_group;
|
||||
std::vector<ruleset_content> dummy_ruleset;
|
||||
std::string managed_url = base64Decode(urlDecode(getUrlArg(argument, "profile_data")));
|
||||
if(managed_url.empty())
|
||||
@@ -1999,10 +2374,12 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
|
||||
proxy = parseProxy(gProxySubscription);
|
||||
eraseElements(dummy_str_array);
|
||||
|
||||
RegexMatchConfigs dummy_regex_array;
|
||||
std::string subInfo;
|
||||
parse_settings parse_set;
|
||||
parse_set.proxy = &proxy;
|
||||
parse_set.exclude_remarks = parse_set.include_remarks = parse_set.stream_rules = parse_set.time_rules = &dummy_str_array;
|
||||
parse_set.exclude_remarks = parse_set.include_remarks = &dummy_str_array;
|
||||
parse_set.stream_rules = parse_set.time_rules = &dummy_regex_array;
|
||||
parse_set.request_header = &request.headers;
|
||||
parse_set.sub_info = &subInfo;
|
||||
parse_set.authorized = !gAPIMode;
|
||||
@@ -2039,7 +2416,8 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
|
||||
ext.tls13 = gTLS13;
|
||||
ext.clash_proxies_style = gClashProxiesStyle;
|
||||
|
||||
proxyToClash(nodes, clash, dummy_str_array, false, ext);
|
||||
ProxyGroupConfigs dummy_groups;
|
||||
proxyToClash(nodes, clash, dummy_groups, false, ext);
|
||||
|
||||
section.clear();
|
||||
ini.GetItems("Proxy", section);
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
#include <map>
|
||||
#include <inja.hpp>
|
||||
|
||||
#include "../config/ruleset.h"
|
||||
#include "../generator/config/subexport.h"
|
||||
#include "../server/webserver.h"
|
||||
|
||||
void refreshRulesets(string_array &ruleset_list, std::vector<ruleset_content> &rca);
|
||||
void refreshRulesets(RulesetConfigs &ruleset_list, std::vector<ruleset_content> &rca);
|
||||
void readConf();
|
||||
int simpleGenerator();
|
||||
std::string convertRuleset(const std::string &content, int type);
|
||||
|
||||
+10
-10
@@ -9,52 +9,52 @@
|
||||
//safety lock for multi-thread
|
||||
std::mutex on_emoji, on_rename, on_stream, on_time;
|
||||
|
||||
extern string_array gEmojis, gRenames;
|
||||
extern string_array gStreamNodeRules, gTimeNodeRules;
|
||||
extern RegexMatchConfigs gEmojis, gRenames;
|
||||
extern RegexMatchConfigs gStreamNodeRules, gTimeNodeRules;
|
||||
|
||||
string_array safe_get_emojis()
|
||||
RegexMatchConfigs safe_get_emojis()
|
||||
{
|
||||
guarded_mutex guard(on_emoji);
|
||||
return gEmojis;
|
||||
}
|
||||
|
||||
string_array safe_get_renames()
|
||||
RegexMatchConfigs safe_get_renames()
|
||||
{
|
||||
guarded_mutex guard(on_rename);
|
||||
return gRenames;
|
||||
}
|
||||
|
||||
string_array safe_get_streams()
|
||||
RegexMatchConfigs safe_get_streams()
|
||||
{
|
||||
guarded_mutex guard(on_stream);
|
||||
return gStreamNodeRules;
|
||||
}
|
||||
|
||||
string_array safe_get_times()
|
||||
RegexMatchConfigs safe_get_times()
|
||||
{
|
||||
guarded_mutex guard(on_time);
|
||||
return gTimeNodeRules;
|
||||
}
|
||||
|
||||
void safe_set_emojis(string_array &data)
|
||||
void safe_set_emojis(RegexMatchConfigs data)
|
||||
{
|
||||
guarded_mutex guard(on_emoji);
|
||||
gEmojis.swap(data);
|
||||
}
|
||||
|
||||
void safe_set_renames(string_array &data)
|
||||
void safe_set_renames(RegexMatchConfigs data)
|
||||
{
|
||||
guarded_mutex guard(on_rename);
|
||||
gRenames.swap(data);
|
||||
}
|
||||
|
||||
void safe_set_streams(string_array &data)
|
||||
void safe_set_streams(RegexMatchConfigs data)
|
||||
{
|
||||
guarded_mutex guard(on_stream);
|
||||
gStreamNodeRules.swap(data);
|
||||
}
|
||||
|
||||
void safe_set_times(string_array &data)
|
||||
void safe_set_times(RegexMatchConfigs data)
|
||||
{
|
||||
guarded_mutex guard(on_time);
|
||||
gTimeNodeRules.swap(data);
|
||||
|
||||
@@ -6,21 +6,22 @@
|
||||
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
#include "../config/regmatch.h"
|
||||
#include "../utils/ini_reader/ini_reader.h"
|
||||
#include "../utils/string.h"
|
||||
|
||||
using guarded_mutex = std::lock_guard<std::mutex>;
|
||||
|
||||
string_array safe_get_emojis();
|
||||
string_array safe_get_renames();
|
||||
string_array safe_get_streams();
|
||||
string_array safe_get_times();
|
||||
RegexMatchConfigs safe_get_emojis();
|
||||
RegexMatchConfigs safe_get_renames();
|
||||
RegexMatchConfigs safe_get_streams();
|
||||
RegexMatchConfigs safe_get_times();
|
||||
YAML::Node safe_get_clash_base();
|
||||
INIReader safe_get_mellow_base();
|
||||
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);
|
||||
void safe_set_emojis(RegexMatchConfigs data);
|
||||
void safe_set_renames(RegexMatchConfigs data);
|
||||
void safe_set_streams(RegexMatchConfigs data);
|
||||
void safe_set_times(RegexMatchConfigs data);
|
||||
std::shared_future<std::string> fetchFileAsync(const std::string &path, const std::string &proxy, int cache_ttl, bool async = false);
|
||||
std::string fetchFile(const std::string &path, const std::string &proxy, int cache_ttl);
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ RWLock cache_rw_lock;
|
||||
long gMaxAllowedDownloadSize = 1048576L;
|
||||
|
||||
//std::string user_agent_str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36";
|
||||
std::string user_agent_str = "subconverter/" VERSION " cURL/" LIBCURL_VERSION;
|
||||
static std::string user_agent_str = "subconverter/" VERSION " cURL/" LIBCURL_VERSION;
|
||||
|
||||
struct curl_progress_data
|
||||
{
|
||||
|
||||
+33
-23
@@ -6,6 +6,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "config/ruleset.h"
|
||||
#include "handler/interfaces.h"
|
||||
#include "handler/webget.h"
|
||||
#include "script/cron.h"
|
||||
@@ -25,10 +26,12 @@
|
||||
extern std::string gPrefPath, gAccessToken, gListenAddress, gGenerateProfiles, gManagedConfigPrefix;
|
||||
extern bool gAPIMode, gGeneratorMode, gCFWChildProcess, gUpdateRulesetOnRequest;
|
||||
extern int gListenPort, gMaxConcurThreads, gMaxPendingConns;
|
||||
extern string_array gCustomRulesets;
|
||||
extern RulesetConfigs gCustomRulesets;
|
||||
extern std::vector<ruleset_content> gRulesetContent;
|
||||
extern bool gEnableCron;
|
||||
|
||||
WebServer webServer;
|
||||
|
||||
#ifndef _WIN32
|
||||
void SetConsoleTitle(const std::string &title)
|
||||
{
|
||||
@@ -105,7 +108,7 @@ void signal_handler(int sig)
|
||||
#endif // _WIN32
|
||||
case SIGTERM:
|
||||
case SIGINT:
|
||||
stop_web_server();
|
||||
webServer.stop_web_server();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -122,10 +125,17 @@ int main(int argc, char *argv[])
|
||||
std::string prgpath = argv[0];
|
||||
setcd(prgpath); //first switch to program directory
|
||||
#endif // _DEBUG
|
||||
if(fileExist("pref.yml"))
|
||||
if(fileExist("pref.toml"))
|
||||
gPrefPath = "pref.toml";
|
||||
else if(fileExist("pref.yml"))
|
||||
gPrefPath = "pref.yml";
|
||||
else if(!fileExist("pref.ini"))
|
||||
{
|
||||
if(fileExist("pref.example.toml"))
|
||||
{
|
||||
fileCopy("pref.example.toml", "pref.toml");
|
||||
gPrefPath = "pref.toml";
|
||||
}
|
||||
if(fileExist("pref.example.yml"))
|
||||
{
|
||||
fileCopy("pref.example.yml", "pref.yml");
|
||||
@@ -173,18 +183,18 @@ int main(int argc, char *argv[])
|
||||
return simpleGenerator();
|
||||
|
||||
/*
|
||||
append_response("GET", "/", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string
|
||||
webServer.append_response("GET", "/", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string
|
||||
{
|
||||
return "subconverter " VERSION " backend\n";
|
||||
});
|
||||
*/
|
||||
|
||||
append_response("GET", "/version", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string
|
||||
webServer.append_response("GET", "/version", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string
|
||||
{
|
||||
return "subconverter " VERSION " backend\n";
|
||||
});
|
||||
|
||||
append_response("GET", "/refreshrules", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string
|
||||
webServer.append_response("GET", "/refreshrules", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string
|
||||
{
|
||||
if(gAccessToken.size())
|
||||
{
|
||||
@@ -199,7 +209,7 @@ int main(int argc, char *argv[])
|
||||
return "done\n";
|
||||
});
|
||||
|
||||
append_response("GET", "/readconf", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string
|
||||
webServer.append_response("GET", "/readconf", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string
|
||||
{
|
||||
if(gAccessToken.size())
|
||||
{
|
||||
@@ -216,7 +226,7 @@ int main(int argc, char *argv[])
|
||||
return "done\n";
|
||||
});
|
||||
|
||||
append_response("POST", "/updateconf", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string
|
||||
webServer.append_response("POST", "/updateconf", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string
|
||||
{
|
||||
if(gAccessToken.size())
|
||||
{
|
||||
@@ -244,7 +254,7 @@ int main(int argc, char *argv[])
|
||||
return "done\n";
|
||||
});
|
||||
|
||||
append_response("GET", "/flushcache", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string
|
||||
webServer.append_response("GET", "/flushcache", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string
|
||||
{
|
||||
if(getUrlArg(request.argument, "token") != gAccessToken)
|
||||
{
|
||||
@@ -255,41 +265,41 @@ int main(int argc, char *argv[])
|
||||
return "done";
|
||||
});
|
||||
|
||||
append_response("GET", "/sub", "text/plain;charset=utf-8", subconverter);
|
||||
webServer.append_response("GET", "/sub", "text/plain;charset=utf-8", subconverter);
|
||||
|
||||
append_response("GET", "/sub2clashr", "text/plain;charset=utf-8", simpleToClashR);
|
||||
webServer.append_response("GET", "/sub2clashr", "text/plain;charset=utf-8", simpleToClashR);
|
||||
|
||||
append_response("GET", "/surge2clash", "text/plain;charset=utf-8", surgeConfToClash);
|
||||
webServer.append_response("GET", "/surge2clash", "text/plain;charset=utf-8", surgeConfToClash);
|
||||
|
||||
append_response("GET", "/getruleset", "text/plain;charset=utf-8", getRuleset);
|
||||
webServer.append_response("GET", "/getruleset", "text/plain;charset=utf-8", getRuleset);
|
||||
|
||||
append_response("GET", "/getprofile", "text/plain;charset=utf-8", getProfile);
|
||||
webServer.append_response("GET", "/getprofile", "text/plain;charset=utf-8", getProfile);
|
||||
|
||||
append_response("GET", "/qx-script", "text/plain;charset=utf-8", getScript);
|
||||
webServer.append_response("GET", "/qx-script", "text/plain;charset=utf-8", getScript);
|
||||
|
||||
append_response("GET", "/qx-rewrite", "text/plain;charset=utf-8", getRewriteRemote);
|
||||
webServer.append_response("GET", "/qx-rewrite", "text/plain;charset=utf-8", getRewriteRemote);
|
||||
|
||||
append_response("GET", "/render", "text/plain;charset=utf-8", renderTemplate);
|
||||
webServer.append_response("GET", "/render", "text/plain;charset=utf-8", renderTemplate);
|
||||
|
||||
append_response("GET", "/convert", "text/plain;charset=utf-8", getConvertedRuleset);
|
||||
webServer.append_response("GET", "/convert", "text/plain;charset=utf-8", getConvertedRuleset);
|
||||
|
||||
if(!gAPIMode)
|
||||
{
|
||||
append_response("GET", "/get", "text/plain;charset=utf-8", [](RESPONSE_CALLBACK_ARGS) -> std::string
|
||||
webServer.append_response("GET", "/get", "text/plain;charset=utf-8", [](RESPONSE_CALLBACK_ARGS) -> std::string
|
||||
{
|
||||
std::string url = urlDecode(getUrlArg(request.argument, "url"));
|
||||
return webGet(url, "");
|
||||
});
|
||||
|
||||
append_response("GET", "/getlocal", "text/plain;charset=utf-8", [](RESPONSE_CALLBACK_ARGS) -> std::string
|
||||
webServer.append_response("GET", "/getlocal", "text/plain;charset=utf-8", [](RESPONSE_CALLBACK_ARGS) -> std::string
|
||||
{
|
||||
return fileGet(urlDecode(getUrlArg(request.argument, "path")));
|
||||
});
|
||||
}
|
||||
|
||||
//append_response("POST", "/create-profile", "text/plain;charset=utf-8", createProfile);
|
||||
//webServer.append_response("POST", "/create-profile", "text/plain;charset=utf-8", createProfile);
|
||||
|
||||
//append_response("GET", "/list-profiles", "text/plain;charset=utf-8", listProfiles);
|
||||
//webServer.append_response("GET", "/list-profiles", "text/plain;charset=utf-8", listProfiles);
|
||||
|
||||
std::string env_port = getEnv("PORT");
|
||||
if(env_port.size())
|
||||
@@ -297,7 +307,7 @@ int main(int argc, char *argv[])
|
||||
listener_args args = {gListenAddress, gListenPort, gMaxPendingConns, gMaxConcurThreads, cron_tick_caller, 200};
|
||||
//std::cout<<"Serving HTTP @ http://"<<listen_address<<":"<<listen_port<<std::endl;
|
||||
writeLog(0, "Startup completed. Serving HTTP @ http://" + gListenAddress + ":" + std::to_string(gListenPort), LOG_LEVEL_INFO);
|
||||
start_web_server_multi(&args);
|
||||
webServer.start_web_server_multi(&args);
|
||||
|
||||
#ifdef _WIN32
|
||||
WSACleanup();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <cmath>
|
||||
#include <time.h>
|
||||
|
||||
#include "../config/regmatch.h"
|
||||
#include "../parser/config/proxy.h"
|
||||
#include "../utils/base64/base64.h"
|
||||
#include "../utils/rapidjson_extra.h"
|
||||
@@ -82,9 +83,9 @@ bool getSubInfoFromHeader(const std::string &header, std::string &result)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool getSubInfoFromNodes(const std::vector<Proxy> &nodes, const string_array &stream_rules, const string_array &time_rules, std::string &result)
|
||||
bool getSubInfoFromNodes(const std::vector<Proxy> &nodes, const RegexMatchConfigs &stream_rules, const RegexMatchConfigs &time_rules, std::string &result)
|
||||
{
|
||||
std::string remarks, pattern, target, stream_info, time_info, retStr;
|
||||
std::string remarks, stream_info, time_info, retStr;
|
||||
string_size spos;
|
||||
|
||||
for(const Proxy &x : nodes)
|
||||
@@ -92,16 +93,11 @@ bool getSubInfoFromNodes(const std::vector<Proxy> &nodes, const string_array &st
|
||||
remarks = x.Remark;
|
||||
if(!stream_info.size())
|
||||
{
|
||||
for(const std::string &y : stream_rules)
|
||||
for(const RegexMatchConfig &y : stream_rules)
|
||||
{
|
||||
spos = y.rfind("|");
|
||||
if(spos == y.npos)
|
||||
continue;
|
||||
pattern = y.substr(0, spos);
|
||||
target = y.substr(spos + 1);
|
||||
if(regMatch(remarks, pattern))
|
||||
if(regMatch(remarks, y.Match))
|
||||
{
|
||||
retStr = regReplace(remarks, pattern, target);
|
||||
retStr = regReplace(remarks, y.Match, y.Replace);
|
||||
if(retStr != remarks)
|
||||
{
|
||||
stream_info = retStr;
|
||||
@@ -116,16 +112,11 @@ bool getSubInfoFromNodes(const std::vector<Proxy> &nodes, const string_array &st
|
||||
remarks = x.Remark;
|
||||
if(!time_info.size())
|
||||
{
|
||||
for(const std::string &y : time_rules)
|
||||
for(const RegexMatchConfig &y : time_rules)
|
||||
{
|
||||
spos = y.rfind("|");
|
||||
if(spos == y.npos)
|
||||
continue;
|
||||
pattern = y.substr(0, spos);
|
||||
target = y.substr(spos + 1);
|
||||
if(regMatch(remarks, pattern))
|
||||
if(regMatch(remarks, y.Match))
|
||||
{
|
||||
retStr = regReplace(remarks, pattern, target);
|
||||
retStr = regReplace(remarks, y.Match, y.Replace);
|
||||
if(retStr != remarks)
|
||||
{
|
||||
time_info = retStr;
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
|
||||
#include "../utils/string.h"
|
||||
#include "config/proxy.h"
|
||||
#include "../config/regmatch.h"
|
||||
|
||||
bool getSubInfoFromHeader(const std::string &header, std::string &result);
|
||||
bool getSubInfoFromNodes(const std::vector<Proxy> &nodes, const string_array &stream_rules, const string_array &time_rules, std::string &result);
|
||||
bool getSubInfoFromNodes(const std::vector<Proxy> &nodes, const RegexMatchConfigs &stream_rules, const RegexMatchConfigs &time_rules, std::string &result);
|
||||
bool getSubInfoFromSSD(const std::string &sub, std::string &result);
|
||||
unsigned long long streamToInt(const std::string &stream);
|
||||
|
||||
|
||||
@@ -96,12 +96,14 @@ void httpConstruct(Proxy &node, const std::string &group, const std::string &rem
|
||||
node.TLSSecure = tls;
|
||||
}
|
||||
|
||||
void trojanConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &password, const std::string &host, bool tlssecure, tribool udp, tribool tfo, tribool scv, tribool tls13)
|
||||
void trojanConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &password, const std::string &network, const std::string &host, const std::string &path, bool tlssecure, tribool udp, tribool tfo, tribool scv, tribool tls13)
|
||||
{
|
||||
commonConstruct(node, ProxyType::Trojan, group, remarks, server, port, udp, tfo, scv, tls13);
|
||||
node.Password = password;
|
||||
node.Host = host;
|
||||
node.TLSSecure = tlssecure;
|
||||
node.TransferProtocol = network.empty() ? "tcp" : network;
|
||||
node.Path = path;
|
||||
}
|
||||
|
||||
void snellConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &password, const std::string &obfs, const std::string &host, tribool udp, tribool tfo, tribool scv)
|
||||
@@ -761,7 +763,7 @@ void explodeTrojan(std::string trojan, Proxy &node)
|
||||
if(group.empty())
|
||||
group = TROJAN_DEFAULT_GROUP;
|
||||
|
||||
trojanConstruct(node, group, remark, server, port, psk, host, true, tribool(), tfo, scv);
|
||||
trojanConstruct(node, group, remark, server, port, psk, "", host, "", true, tribool(), tfo, scv);
|
||||
}
|
||||
|
||||
void explodeQuan(const std::string &quan, Proxy &node)
|
||||
@@ -911,10 +913,12 @@ void explodeNetch(std::string netch, Proxy &node)
|
||||
break;
|
||||
case "Trojan"_hash:
|
||||
host = GetMember(json, "Host");
|
||||
path = GetMember(json, "Path");
|
||||
transprot = GetMember(json, "TransferProtocol");
|
||||
tls = GetMember(json, "TLSSecure");
|
||||
if(group.empty())
|
||||
group = TROJAN_DEFAULT_GROUP;
|
||||
trojanConstruct(node, group, remark, address, port, password, host, tls == "true", udp, tfo, scv);
|
||||
trojanConstruct(node, group, remark, address, port, password, transprot, host, path, tls == "true", udp, tfo, scv);
|
||||
break;
|
||||
case "Snell"_hash:
|
||||
obfs = GetMember(json, "OBFS");
|
||||
@@ -968,9 +972,18 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes)
|
||||
edge.clear();
|
||||
break;
|
||||
case "ws"_hash:
|
||||
path = singleproxy["ws-path"].IsDefined() ? safe_as<std::string>(singleproxy["ws-path"]) : "/";
|
||||
singleproxy["ws-headers"]["Host"] >>= host;
|
||||
singleproxy["ws-headers"]["Edge"] >>= edge;
|
||||
if(singleproxy["ws-opts"].IsDefined())
|
||||
{
|
||||
path = singleproxy["ws-opts"]["path"].IsDefined() ? safe_as<std::string>(singleproxy["ws-opts"]["path"]) : "/";
|
||||
singleproxy["ws-opts"]["headers"]["Host"] >>= host;
|
||||
singleproxy["ws-opts"]["headers"]["Edge"] >>= edge;
|
||||
}
|
||||
else
|
||||
{
|
||||
path = singleproxy["ws-path"].IsDefined() ? safe_as<std::string>(singleproxy["ws-path"]) : "/";
|
||||
singleproxy["ws-headers"]["Host"] >>= host;
|
||||
singleproxy["ws-headers"]["Edge"] >>= edge;
|
||||
}
|
||||
break;
|
||||
case "h2"_hash:
|
||||
singleproxy["h2-opts"]["path"] >>= path;
|
||||
@@ -1097,8 +1110,18 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes)
|
||||
group = TROJAN_DEFAULT_GROUP;
|
||||
singleproxy["password"] >>= password;
|
||||
singleproxy["sni"] >>= host;
|
||||
if(safe_as<std::string>(singleproxy["network"]) == "grpc")
|
||||
{
|
||||
net = "grpc";
|
||||
singleproxy["grpc-opts"]["grpc-service-name"] >>= path;
|
||||
}
|
||||
else
|
||||
{
|
||||
net = "tcp";
|
||||
path.clear();
|
||||
}
|
||||
|
||||
trojanConstruct(node, group, ps, server, port, password, host, true, udp, tfo, scv);
|
||||
trojanConstruct(node, group, ps, server, port, password, net, host, path, true, udp, tfo, scv);
|
||||
break;
|
||||
case "snell"_hash:
|
||||
group = SNELL_DEFAULT_GROUP;
|
||||
@@ -1574,7 +1597,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes)
|
||||
if(host.empty() && !isIPv4(server) && !isIPv6(server))
|
||||
host = server;
|
||||
|
||||
trojanConstruct(node, TROJAN_DEFAULT_GROUP, remarks, server, port, password, host, true, udp, tfo, scv);
|
||||
trojanConstruct(node, TROJAN_DEFAULT_GROUP, remarks, server, port, password, "", host, "", true, udp, tfo, scv);
|
||||
break;
|
||||
case "snell"_hash:
|
||||
server = trim(configs[1]);
|
||||
@@ -1840,7 +1863,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes)
|
||||
if(host.empty() && !isIPv4(server) && !isIPv6(server))
|
||||
host = server;
|
||||
|
||||
trojanConstruct(node, TROJAN_DEFAULT_GROUP, remarks, server, port, password, host, tls == "true", udp, tfo, scv, tls13);
|
||||
trojanConstruct(node, TROJAN_DEFAULT_GROUP, remarks, server, port, password, "", host, "", tls == "true", udp, tfo, scv, tls13);
|
||||
break;
|
||||
case "http"_hash: //quantumult x style http links
|
||||
server = trim(configs[0].substr(0, configs[0].rfind(":")));
|
||||
|
||||
@@ -25,7 +25,7 @@ void ssrConstruct(Proxy &node, const std::string &group, const std::string &rema
|
||||
void ssConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &password, const std::string &method, const std::string &plugin, const std::string &pluginopts, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool());
|
||||
void socksConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &username, const std::string &password, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool());
|
||||
void httpConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &username, const std::string &password, bool tls, tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool());
|
||||
void trojanConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &password, const std::string &host, bool tlssecure, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool());
|
||||
void trojanConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &password, const std::string &network, const std::string &host, const std::string &path, bool tlssecure, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(), tribool tls13 = tribool());
|
||||
void snellConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server, const std::string &port, const std::string &password, const std::string &obfs, const std::string &host, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool());
|
||||
void explodeVmess(std::string vmess, Proxy &node);
|
||||
void explodeSSR(std::string ssr, Proxy &node);
|
||||
|
||||
+13
-20
@@ -2,6 +2,7 @@
|
||||
#include <iostream>
|
||||
#include <libcron/Cron.h>
|
||||
|
||||
#include "../config/crontask.h"
|
||||
#include "../handler/interfaces.h"
|
||||
#include "../handler/multithread.h"
|
||||
#include "../server/webserver.h"
|
||||
@@ -11,7 +12,7 @@
|
||||
#include "script_quickjs.h"
|
||||
|
||||
extern bool gEnableCron;
|
||||
extern string_array gCronTasks;
|
||||
extern CronTaskConfigs gCronTasks;
|
||||
extern std::string gProxyConfig, gAccessToken;
|
||||
extern int gCacheConfig;
|
||||
|
||||
@@ -48,13 +49,9 @@ int timeout_checker(JSRuntime *rt, void *opaque)
|
||||
void refresh_schedule()
|
||||
{
|
||||
cron.clear_schedules();
|
||||
for(std::string &x : gCronTasks)
|
||||
for(const CronTaskConfig &x : gCronTasks)
|
||||
{
|
||||
string_array arguments = split(x, "`");
|
||||
if(arguments.size() < 3)
|
||||
continue;
|
||||
std::string &name = arguments[0], &cronexp = arguments[1], &path = arguments[2];
|
||||
cron.add_schedule(name, cronexp, [=](auto &)
|
||||
cron.add_schedule(x.Name, x.CronExp, [=](auto &)
|
||||
{
|
||||
qjs::Runtime runtime;
|
||||
qjs::Context context(runtime);
|
||||
@@ -64,18 +61,18 @@ void refresh_schedule()
|
||||
script_context_init(context);
|
||||
defer(script_cleanup(context);)
|
||||
std::string proxy = parseProxy(gProxyConfig);
|
||||
std::string script = fetchFile(path, proxy, gCacheConfig);
|
||||
std::string script = fetchFile(x.Path, proxy, gCacheConfig);
|
||||
if(script.empty())
|
||||
{
|
||||
writeLog(0, "Script '" + name + "' run failed: file is empty or not exist!", LOG_LEVEL_WARNING);
|
||||
writeLog(0, "Script '" + x.Name + "' run failed: file is empty or not exist!", LOG_LEVEL_WARNING);
|
||||
return;
|
||||
}
|
||||
script_info info;
|
||||
if(arguments.size() >= 4 && !arguments[3].empty())
|
||||
if(x.Timeout > 0)
|
||||
{
|
||||
info.begin_time = time(NULL);
|
||||
info.timeout = to_int(arguments[3], 0);
|
||||
info.name = name;
|
||||
info.timeout = x.Timeout;
|
||||
info.name = x.Name;
|
||||
JS_SetInterruptHandler(JS_GetRuntime(context.ctx), timeout_checker, &info);
|
||||
}
|
||||
context.eval(script);
|
||||
@@ -109,19 +106,15 @@ std::string list_cron_schedule(RESPONSE_CALLBACK_ARGS)
|
||||
writer.Int(200);
|
||||
writer.Key("tasks");
|
||||
writer.StartArray();
|
||||
for(std::string &x : gCronTasks)
|
||||
for(const CronTaskConfig &x : gCronTasks)
|
||||
{
|
||||
string_array arguments = split(x, "`");
|
||||
if(arguments.size() < 3)
|
||||
continue;
|
||||
writer.StartObject();
|
||||
std::string &name = arguments[0], &cronexp = arguments[1], &path = arguments[2];
|
||||
writer.Key("name");
|
||||
writer.String(name.data());
|
||||
writer.String(x.Name.data());
|
||||
writer.Key("cronexp");
|
||||
writer.String(cronexp.data());
|
||||
writer.String(x.CronExp.data());
|
||||
writer.Key("path");
|
||||
writer.String(path.data());
|
||||
writer.String(x.Path.data());
|
||||
writer.EndObject();
|
||||
}
|
||||
writer.EndArray();
|
||||
|
||||
+40
-6
@@ -3,8 +3,13 @@
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <atomic>
|
||||
#include <event2/http.h>
|
||||
#include <curl/curlver.h>
|
||||
|
||||
#include "../utils/map_extra.h"
|
||||
#include "../utils/string.h"
|
||||
#include "../version.h"
|
||||
|
||||
struct Request
|
||||
{
|
||||
@@ -36,11 +41,40 @@ struct listener_args
|
||||
uint32_t looper_interval = 200;
|
||||
};
|
||||
|
||||
void append_response(const std::string &method, const std::string &uri, const std::string &content_type, response_callback response);
|
||||
void append_redirect(const std::string &uri, const std::string &target);
|
||||
void reset_redirect();
|
||||
int start_web_server(void *argv);
|
||||
int start_web_server_multi(void *argv);
|
||||
void stop_web_server();
|
||||
struct responseRoute
|
||||
{
|
||||
std::string method;
|
||||
std::string path;
|
||||
std::string content_type;
|
||||
response_callback rc;
|
||||
};
|
||||
|
||||
class WebServer
|
||||
{
|
||||
public:
|
||||
std::string user_agent_str = "subconverter/" VERSION " cURL/" LIBCURL_VERSION;
|
||||
std::atomic_bool SERVER_EXIT_FLAG{false};
|
||||
|
||||
// file server
|
||||
bool serve_file = false;
|
||||
std::string serve_file_root;
|
||||
|
||||
// basic authentication
|
||||
bool require_auth = false;
|
||||
std::string auth_user, auth_password, auth_realm = "Please enter username and password:";
|
||||
|
||||
void append_response(const std::string &method, const std::string &uri, const std::string &content_type, response_callback response);
|
||||
void append_redirect(const std::string &uri, const std::string &target);
|
||||
void reset_redirect();
|
||||
int start_web_server(void *argv);
|
||||
int start_web_server_multi(void *argv);
|
||||
void stop_web_server();
|
||||
private:
|
||||
int serveFile(const std::string &filename, std::string &content_type, std::string &return_data);
|
||||
inline int process_request(Request &request, Response &response, std::string &return_data);
|
||||
void on_request(evhttp_request *req, void *args);
|
||||
std::vector<responseRoute> responses;
|
||||
string_map redirect_map;
|
||||
};
|
||||
|
||||
#endif // WEBSERVER_H_INCLUDED
|
||||
@@ -14,7 +14,9 @@
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
|
||||
#include "../utils/base64/base64.h"
|
||||
#include "../utils/file_extra.h"
|
||||
#include "../utils/logger.h"
|
||||
#include "../utils/stl_extra.h"
|
||||
@@ -23,12 +25,22 @@
|
||||
#include "socket.h"
|
||||
#include "webserver.h"
|
||||
|
||||
extern std::string user_agent_str;
|
||||
std::atomic_bool SERVER_EXIT_FLAG(false);
|
||||
template <typename Lambda, class Ret, class... Args, class Pointer = Ret (*)(Args...)>
|
||||
Pointer deduced_wrap(
|
||||
const std::function<Ret(Args...)> &func)
|
||||
{
|
||||
static auto saved = func;
|
||||
static Pointer p = [](Args... args) {
|
||||
return saved(std::forward<Args>(args)...);
|
||||
};
|
||||
return p;
|
||||
}
|
||||
|
||||
// file server
|
||||
bool gServeFile = false;
|
||||
std::string gServeFileRoot;
|
||||
template <typename Lambda>
|
||||
auto *wrap(Lambda &&func)
|
||||
{
|
||||
return deduced_wrap<Lambda>(std::function{func});
|
||||
}
|
||||
|
||||
struct MIME_type
|
||||
{
|
||||
@@ -78,9 +90,9 @@ std::string checkMIMEType(const std::string &filename)
|
||||
return "application/octet-stream";
|
||||
}
|
||||
|
||||
int serveFile(const std::string &filename, std::string &content_type, std::string &return_data)
|
||||
int WebServer::serveFile(const std::string &filename, std::string &content_type, std::string &return_data)
|
||||
{
|
||||
std::string realname = gServeFileRoot + filename;
|
||||
std::string realname = serve_file_root + filename;
|
||||
if(filename.compare("/") == 0)
|
||||
realname += "index.html";
|
||||
if(!fileExist(realname))
|
||||
@@ -92,17 +104,6 @@ int serveFile(const std::string &filename, std::string &content_type, std::strin
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct responseRoute
|
||||
{
|
||||
std::string method;
|
||||
std::string path;
|
||||
std::string content_type;
|
||||
response_callback rc;
|
||||
};
|
||||
|
||||
std::vector<responseRoute> responses;
|
||||
string_map redirect_map;
|
||||
|
||||
const char *request_header_blacklist[] = {"host", "accept", "accept-encoding"};
|
||||
|
||||
static inline void buffer_cleanup(struct evbuffer *eb)
|
||||
@@ -114,7 +115,7 @@ static inline void buffer_cleanup(struct evbuffer *eb)
|
||||
#endif // MALLOC_TRIM
|
||||
}
|
||||
|
||||
static inline int process_request(Request &request, Response &response, std::string &return_data)
|
||||
inline int WebServer::process_request(Request &request, Response &response, std::string &return_data)
|
||||
{
|
||||
writeLog(0, "handle_cmd: " + request.method + " handle_uri: " + request.url, LOG_LEVEL_VERBOSE);
|
||||
|
||||
@@ -125,13 +126,17 @@ static inline int process_request(Request &request, Response &response, std::str
|
||||
request.url.erase(pos);
|
||||
}
|
||||
|
||||
if(request.method == "OPTIONS")
|
||||
{
|
||||
for(responseRoute &x : responses)
|
||||
if(matchSpaceSeparatedList(replaceAllDistinct(request.postdata, ",", ""), x.method) && x.path == request.url)
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(responseRoute &x : responses)
|
||||
{
|
||||
if(request.method == "OPTIONS" && matchSpaceSeparatedList(replaceAllDistinct(request.postdata, ",", ""), x.method) && x.path == request.url)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if(x.method == request.method && x.path == request.url)
|
||||
if(x.method == request.method && x.path == request.url)
|
||||
{
|
||||
response_callback &rc = x.rc;
|
||||
return_data = rc(request, response);
|
||||
@@ -151,11 +156,10 @@ static inline int process_request(Request &request, Response &response, std::str
|
||||
else
|
||||
return_data += "?" + request.argument;
|
||||
}
|
||||
response.content_type = "REDIRECT";
|
||||
return 0;
|
||||
return 2;
|
||||
}
|
||||
|
||||
if(gServeFile)
|
||||
if(serve_file)
|
||||
{
|
||||
if(request.method.compare("GET") == 0 && serveFile(request.url, response.content_type, return_data) == 0)
|
||||
return 0;
|
||||
@@ -164,9 +168,10 @@ static inline int process_request(Request &request, Response &response, std::str
|
||||
return -1;
|
||||
}
|
||||
|
||||
void OnReq(evhttp_request *req, void *args)
|
||||
void WebServer::on_request(evhttp_request *req, void *args)
|
||||
{
|
||||
(void)args;
|
||||
static std::string auth_token = "Basic " + base64Encode(auth_user + ":" + auth_password);
|
||||
const char *req_content_type = evhttp_find_header(req->input_headers, "Content-Type"), *req_ac_method = evhttp_find_header(req->input_headers, "Access-Control-Request-Method");
|
||||
const char *uri = req->uri, *internal_flag = evhttp_find_header(req->input_headers, "SubConverter-Request");
|
||||
|
||||
@@ -176,26 +181,41 @@ void OnReq(evhttp_request *req, void *args)
|
||||
//std::cerr<<"Accept connection from client "<<client_ip<<":"<<client_port<<"\n";
|
||||
writeLog(0, "Accept connection from client " + std::string(client_ip) + ":" + std::to_string(client_port), LOG_LEVEL_DEBUG);
|
||||
|
||||
if(internal_flag != NULL)
|
||||
if (internal_flag != nullptr)
|
||||
{
|
||||
evhttp_send_error(req, 500, "Loop request detected!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (require_auth)
|
||||
{
|
||||
const char *auth = evhttp_find_header(req->input_headers, "Authorization");
|
||||
if (auth == nullptr || auth_token != auth)
|
||||
{
|
||||
evhttp_add_header(req->output_headers, "WWW-Authenticate", ("Basic realm=\"" + auth_realm + "\"").data());
|
||||
auto buffer = evhttp_request_get_output_buffer(req);
|
||||
evbuffer_add_printf(buffer, "Unauthorized");
|
||||
evhttp_send_reply(req, 401, nullptr, buffer);
|
||||
buffer_cleanup(buffer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Request request;
|
||||
Response response;
|
||||
if(EVBUFFER_LENGTH(req->input_buffer) != 0)
|
||||
size_t buffer_len = evbuffer_get_length(req->input_buffer);
|
||||
if (buffer_len != 0)
|
||||
{
|
||||
request.postdata.assign((char *)EVBUFFER_DATA(req->input_buffer), EVBUFFER_LENGTH(req->input_buffer));
|
||||
if(req_content_type != NULL && strcmp(req_content_type, "application/x-www-form-urlencoded") == 0)
|
||||
request.postdata.assign(reinterpret_cast<char*>(evbuffer_pullup(req->input_buffer, -1)), buffer_len);
|
||||
if(req_content_type != nullptr && strcmp(req_content_type, "application/x-www-form-urlencoded") == 0)
|
||||
request.postdata = urlDecode(request.postdata);
|
||||
}
|
||||
else if(req_ac_method != NULL)
|
||||
else if (req_ac_method != nullptr)
|
||||
{
|
||||
request.postdata.assign(req_ac_method);
|
||||
}
|
||||
|
||||
switch(req->type)
|
||||
switch (req->type)
|
||||
{
|
||||
case EVHTTP_REQ_GET: request.method = "GET"; break;
|
||||
case EVHTTP_REQ_POST: request.method = "POST"; break;
|
||||
@@ -218,54 +238,50 @@ void OnReq(evhttp_request *req, void *args)
|
||||
|
||||
std::string return_data;
|
||||
int retVal = process_request(request, response, return_data);
|
||||
std::string content_type = response.content_type;
|
||||
std::string &content_type = response.content_type;
|
||||
|
||||
auto *OutBuf = evhttp_request_get_output_buffer(req);
|
||||
//struct evbuffer *OutBuf = evbuffer_new();
|
||||
if (!OutBuf)
|
||||
auto *output_buffer = evhttp_request_get_output_buffer(req);
|
||||
if (!output_buffer)
|
||||
{
|
||||
evhttp_send_error(req, HTTP_INTERNAL, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
for(auto &x : response.headers)
|
||||
for (auto &x : response.headers)
|
||||
evhttp_add_header(req->output_headers, x.first.data(), x.second.data());
|
||||
|
||||
switch(retVal)
|
||||
switch (retVal)
|
||||
{
|
||||
case 1: //found OPTIONS
|
||||
evhttp_add_header(req->output_headers, "Access-Control-Allow-Origin", "*");
|
||||
evhttp_add_header(req->output_headers, "Access-Control-Allow-Headers", "*");
|
||||
evhttp_send_reply(req, response.status_code, "", NULL);
|
||||
evhttp_send_reply(req, response.status_code, nullptr, nullptr);
|
||||
break;
|
||||
case 2: //found redirect
|
||||
evhttp_add_header(req->output_headers, "Location", return_data.c_str());
|
||||
evhttp_send_reply(req, HTTP_MOVETEMP, nullptr, nullptr);
|
||||
break;
|
||||
case 0: //found normal
|
||||
if(content_type.size())
|
||||
{
|
||||
if(content_type == "REDIRECT")
|
||||
{
|
||||
evhttp_add_header(req->output_headers, "Location", return_data.c_str());
|
||||
evhttp_send_reply(req, HTTP_MOVETEMP, "", NULL);
|
||||
buffer_cleanup(OutBuf);
|
||||
return;
|
||||
}
|
||||
else
|
||||
evhttp_add_header(req->output_headers, "Content-Type", content_type.c_str());
|
||||
}
|
||||
if (content_type.size())
|
||||
evhttp_add_header(req->output_headers, "Content-Type", content_type.c_str());
|
||||
evhttp_add_header(req->output_headers, "Access-Control-Allow-Origin", "*");
|
||||
evhttp_add_header(req->output_headers, "Connection", "close");
|
||||
evbuffer_add(OutBuf, return_data.data(), return_data.size());
|
||||
evhttp_send_reply(req, response.status_code, "", OutBuf);
|
||||
evbuffer_add(output_buffer, return_data.data(), return_data.size());
|
||||
evhttp_send_reply(req, response.status_code, nullptr, output_buffer);
|
||||
break;
|
||||
case -1: //not found
|
||||
return_data = "File not found.";
|
||||
evbuffer_add(OutBuf, return_data.data(), return_data.size());
|
||||
evhttp_send_reply(req, HTTP_NOTFOUND, "", OutBuf);
|
||||
evbuffer_add(output_buffer, return_data.data(), return_data.size());
|
||||
evhttp_send_reply(req, HTTP_NOTFOUND, nullptr, output_buffer);
|
||||
//evhttp_send_error(req, HTTP_NOTFOUND, "Resource not found");
|
||||
break;
|
||||
default: //undefined behavior
|
||||
evhttp_send_error(req, HTTP_INTERNAL, "");
|
||||
evhttp_send_error(req, HTTP_INTERNAL, nullptr);
|
||||
}
|
||||
buffer_cleanup(OutBuf);
|
||||
buffer_cleanup(output_buffer);
|
||||
}
|
||||
|
||||
int start_web_server(void *argv)
|
||||
int WebServer::start_web_server(void *argv)
|
||||
{
|
||||
struct listener_args *args = reinterpret_cast<listener_args*>(argv);
|
||||
std::string listen_address = args->listen_address;
|
||||
@@ -278,17 +294,19 @@ int start_web_server(void *argv)
|
||||
}
|
||||
const char *SrvAddress = listen_address.c_str();
|
||||
std::uint16_t SrvPort = port;
|
||||
std::unique_ptr<evhttp, decltype(&evhttp_free)> Server(evhttp_start(SrvAddress, SrvPort), &evhttp_free);
|
||||
if (!Server)
|
||||
std::unique_ptr<evhttp, decltype(&evhttp_free)> server(evhttp_start(SrvAddress, SrvPort), &evhttp_free);
|
||||
if (!server)
|
||||
{
|
||||
//std::cerr << "Failed to init http server." << std::endl;
|
||||
writeLog(0, "Failed to init http server.", LOG_LEVEL_FATAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
evhttp_set_allowed_methods(Server.get(), EVHTTP_REQ_GET | EVHTTP_REQ_POST | EVHTTP_REQ_OPTIONS | EVHTTP_REQ_PUT | EVHTTP_REQ_PATCH | EVHTTP_REQ_DELETE);
|
||||
evhttp_set_gencb(Server.get(), OnReq, nullptr);
|
||||
evhttp_set_timeout(Server.get(), 30);
|
||||
auto call_on_request = [&](evhttp_request *req, void *args) { on_request(req, args); };
|
||||
|
||||
evhttp_set_allowed_methods(server.get(), EVHTTP_REQ_GET | EVHTTP_REQ_POST | EVHTTP_REQ_OPTIONS | EVHTTP_REQ_PUT | EVHTTP_REQ_PATCH | EVHTTP_REQ_DELETE);
|
||||
evhttp_set_gencb(server.get(), wrap(call_on_request), nullptr);
|
||||
evhttp_set_timeout(server.get(), 30);
|
||||
if (event_dispatch() == -1)
|
||||
{
|
||||
//std::cerr << "Failed to run message loop." << std::endl;
|
||||
@@ -303,7 +321,7 @@ void* httpserver_dispatch(void *arg)
|
||||
{
|
||||
event_base_dispatch(reinterpret_cast<event_base*>(arg));
|
||||
event_base_free(reinterpret_cast<event_base*>(arg)); //free resources
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int httpserver_bindsocket(std::string listen_address, int listen_port, int backlog)
|
||||
@@ -345,44 +363,45 @@ int httpserver_bindsocket(std::string listen_address, int listen_port, int backl
|
||||
return nfd;
|
||||
}
|
||||
|
||||
int start_web_server_multi(void *argv)
|
||||
int WebServer::start_web_server_multi(void *argv)
|
||||
{
|
||||
struct listener_args *args = reinterpret_cast<listener_args*>(argv);
|
||||
std::string listen_address = args->listen_address;
|
||||
int port = args->port, nthreads = args->max_workers;
|
||||
int i;
|
||||
int port = args->port, nthreads = args->max_workers, max_conn = args->max_conn;
|
||||
|
||||
int nfd = httpserver_bindsocket(listen_address, port, args->max_conn);
|
||||
auto call_on_request = [&](evhttp_request *req, void *args) { on_request(req, args); };
|
||||
|
||||
int nfd = httpserver_bindsocket(listen_address, port, max_conn);
|
||||
if (nfd < 0)
|
||||
return -1;
|
||||
|
||||
pthread_t ths[nthreads];
|
||||
struct event_base *base[nthreads];
|
||||
for (i = 0; i < nthreads; i++)
|
||||
for (int i = 0; i < nthreads; i++)
|
||||
{
|
||||
base[i] = event_init();
|
||||
if (base[i] == NULL)
|
||||
if (base[i] == nullptr)
|
||||
return -1;
|
||||
struct evhttp *httpd = evhttp_new(base[i]);
|
||||
if (httpd == NULL)
|
||||
if (httpd == nullptr)
|
||||
return -1;
|
||||
if (evhttp_accept_socket(httpd, nfd) != 0)
|
||||
return -1;
|
||||
|
||||
evhttp_set_allowed_methods(httpd, EVHTTP_REQ_GET | EVHTTP_REQ_POST | EVHTTP_REQ_OPTIONS);
|
||||
evhttp_set_gencb(httpd, OnReq, nullptr);
|
||||
evhttp_set_allowed_methods(httpd, EVHTTP_REQ_GET | EVHTTP_REQ_POST | EVHTTP_REQ_OPTIONS | EVHTTP_REQ_PUT | EVHTTP_REQ_PATCH | EVHTTP_REQ_DELETE);
|
||||
evhttp_set_gencb(httpd, wrap(call_on_request), nullptr);
|
||||
evhttp_set_timeout(httpd, 30);
|
||||
if (pthread_create(&ths[i], NULL, httpserver_dispatch, base[i]) != 0)
|
||||
if (pthread_create(&ths[i], nullptr, httpserver_dispatch, base[i]) != 0)
|
||||
return -1;
|
||||
}
|
||||
while (!SERVER_EXIT_FLAG)
|
||||
{
|
||||
if(args->looper_callback != nullptr)
|
||||
if (args->looper_callback != nullptr)
|
||||
args->looper_callback();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(args->looper_interval)); //block forever until receive stop signal
|
||||
}
|
||||
|
||||
for (i = 0; i < nthreads; i++)
|
||||
for (int i = 0; i < nthreads; i++)
|
||||
event_base_loopbreak(base[i]); //stop the loop
|
||||
|
||||
shutdown(nfd, SD_BOTH); //stop accept call
|
||||
@@ -391,12 +410,12 @@ int start_web_server_multi(void *argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void stop_web_server()
|
||||
void WebServer::stop_web_server()
|
||||
{
|
||||
SERVER_EXIT_FLAG = true;
|
||||
}
|
||||
|
||||
void append_response(const std::string &method, const std::string &uri, const std::string &content_type, response_callback response)
|
||||
void WebServer::append_response(const std::string &method, const std::string &uri, const std::string &content_type, response_callback response)
|
||||
{
|
||||
responseRoute rr;
|
||||
rr.method = method;
|
||||
@@ -406,12 +425,12 @@ void append_response(const std::string &method, const std::string &uri, const st
|
||||
responses.emplace_back(std::move(rr));
|
||||
}
|
||||
|
||||
void append_redirect(const std::string &uri, const std::string &target)
|
||||
void WebServer::append_redirect(const std::string &uri, const std::string &target)
|
||||
{
|
||||
redirect_map[uri] = target;
|
||||
}
|
||||
|
||||
void reset_redirect()
|
||||
void WebServer::reset_redirect()
|
||||
{
|
||||
eraseElements(redirect_map);
|
||||
}
|
||||
@@ -34,6 +34,8 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool operator==(const tribool& rhs){ return _M_VALUE == rhs._M_VALUE; }
|
||||
|
||||
operator bool() const { return _M_VALUE == 3; }
|
||||
|
||||
bool is_undef() const { return _M_VALUE <= 1; }
|
||||
|
||||
Reference in new issue
Block a user