#include #include #include #include #include #include "socket.h" #include "misc.h" #include "nodeinfo.h" #include "speedtestutil.h" #include "nodemanip.h" #include "ini_reader.h" #include "webget.h" #include "webserver.h" #include "subexport.h" #include "multithread.h" #include "version.h" //common settings std::string pref_path = "pref.ini"; string_array def_exclude_remarks, def_include_remarks, rulesets; std::vector ruleset_content_array; std::string listen_address = "127.0.0.1", default_url, managed_config_prefix; int listen_port = 25500, max_pending_connections = 10, max_concurrent_threads = 4; bool api_mode = true, write_managed_config = false, update_ruleset_on_request = false, overwrite_original_rules = true; bool print_debug_info = false, cfw_child_process = false; extern std::string custom_group; //multi-thread lock extern std::mutex on_configuring; //preferences string_array renames, emojis; bool add_emoji = false, remove_old_emoji = false, append_proxy_type = true; bool udp_flag = false, tfo_flag = false, do_sort = false; std::string proxy_ruleset, proxy_subscription; std::string clash_rule_base; string_array clash_extra_group; std::string surge_rule_base, surfboard_rule_base, mellow_rule_base; std::string surge_ssr_path; #ifndef _WIN32 void SetConsoleTitle(std::string title) { system(std::string("echo \"\\033]0;" + title + "\\007\\c\"").data()); } #endif // _WIN32 void setcd(char *argv[]) { std::string path; char szTmp[1024]; #ifndef _WIN32 path.assign(argv[0]); if(path[0] != '/') { getcwd(szTmp, 1023); path.assign(szTmp); path.append("/"); path.append(argv[0]); } path = path.substr(0, path.rfind("/") + 1); #else GetModuleFileName(NULL, szTmp, 1023); strrchr(szTmp, '\\')[1] = '\0'; path.assign(szTmp); #endif // _WIN32 chdir(path.data()); } std::string refreshRulesets(string_array &ruleset_list, std::vector &rca) { eraseElements(rca); std::string rule_group, rule_url; ruleset_content rc; std::string proxy; if(proxy_ruleset == "SYSTEM") proxy = getSystemProxy(); else if(proxy_ruleset == "NONE") proxy = ""; else proxy = proxy_ruleset; for(std::string &x : ruleset_list) { /* vArray = split(x, ","); if(vArray.size() != 2) continue; rule_group = trim(vArray[0]); rule_url = trim(vArray[1]); */ if(x.find(",") == x.npos) continue; rule_group = trim(x.substr(0, x.find(","))); rule_url = trim(x.substr(x.find(",") + 1)); if(rule_url.find("[]") == 0) { std::cerr<<"Adding rule '"< rca; if(!url.size()) url = default_url; if(!url.size() || !target.size()) return "Invalid request!"; if(!api_mode || cfw_child_process) readConf(); if(groups.size()) { extra_group = split(groups, "@"); if(!extra_group.size()) extra_group = clash_extra_group; } else extra_group = clash_extra_group; if(ruleset.size()) { extra_ruleset = split(ruleset, "@"); if(!extra_ruleset.size()) { if(update_ruleset_on_request || cfw_child_process) refreshRulesets(rulesets, ruleset_content_array); rca = ruleset_content_array; } else { refreshRulesets(extra_ruleset, rca); } } else { if(update_ruleset_on_request || cfw_child_process) refreshRulesets(rulesets, ruleset_content_array); rca = ruleset_content_array; } extra_settings ext; if(emoji.size()) { ext.add_emoji = ext.remove_emoji = emoji == "true"; } else { ext.add_emoji = add_emoji; ext.remove_emoji = remove_old_emoji; } if(append_type.size()) ext.append_proxy_type = append_type == "true"; else ext.append_proxy_type = append_proxy_type; std::string proxy; if(proxy_subscription == "SYSTEM") proxy = getSystemProxy(); else if(proxy_subscription == "NONE") proxy = ""; else proxy = proxy_subscription; ext.tfo = tfo.size() ? tfo == "true" : tfo_flag; ext.udp = udp.size() ? udp == "true" : udp_flag; ext.sort_flag = sort_flag.size() ? sort_flag == "true" : do_sort; ext.nodelist = nodelist == "true"; ext.surge_ssr_path = surge_ssr_path; string_array urls = split(url, "|"); std::vector nodes; int groupID = 0; if(include.size() && regValid(include)) include_remarks.emplace_back(include); else include_remarks = def_include_remarks; if(exclude.size() && regValid(exclude)) exclude_remarks.emplace_back(exclude); else exclude_remarks = def_exclude_remarks; if(group.size()) custom_group = group; for(std::string &x : urls) { x = trim(x); std::cerr<<"Fetching node data from url '"< std::string { return refreshRulesets(rulesets, ruleset_content_array); }); append_response("GET", "/readconf", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string { readConf(); return "done"; }); append_response("GET", "/sub", "text/plain;charset=utf-8", subconverter); append_response("GET", "/clash", "text/plain;charset=utf-8", [](RESPONSE_CALLBACK_ARGS) -> std::string { return subconverter(argument + "&target=clash", postdata); }); append_response("GET", "/clashr", "text/plain;charset=utf-8", [](RESPONSE_CALLBACK_ARGS) -> std::string { return subconverter(argument + "&target=clashr", postdata); }); append_response("GET", "/surge", "text/plain;charset=utf-8", [](RESPONSE_CALLBACK_ARGS) -> std::string { return subconverter(argument + "&target=surge", postdata); }); append_response("GET", "/surfboard", "text/plain;charset=utf-8", [](RESPONSE_CALLBACK_ARGS) -> std::string { return subconverter(argument + "&target=surfboard", postdata); }); append_response("GET", "/mellow", "text/plain;charset=utf-8", [](RESPONSE_CALLBACK_ARGS) -> std::string { return subconverter(argument + "&target=mellow", postdata); }); append_response("GET", "/ss", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string { return subconverter(argument + "&target=ss", postdata); }); append_response("GET", "/ssr", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string { return subconverter(argument + "&target=ssr", postdata); }); append_response("GET", "/v2ray", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string { return subconverter(argument + "&target=v2ray", postdata); }); append_response("GET", "/quan", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string { return subconverter(argument + "&target=quan", postdata); }); append_response("GET", "/quanx", "text/plain;charset=utf-8", [](RESPONSE_CALLBACK_ARGS) -> std::string { return subconverter(argument + "&target=quanx", postdata); }); append_response("GET", "/ssd", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string { return subconverter(argument + "&target=ssd", postdata); }); if(!api_mode) { append_response("GET", "/get", "text/plain;charset=utf-8", [](RESPONSE_CALLBACK_ARGS) -> std::string { std::string url = UrlDecode(getUrlArg(argument, "url")); return webGet(url, ""); }); append_response("GET", "/getlocal", "text/plain;charset=utf-8", [](RESPONSE_CALLBACK_ARGS) -> std::string { return fileGet(UrlDecode(getUrlArg(argument, "path"))); }); } listener_args args = {listen_address, listen_port, max_pending_connections, max_concurrent_threads}; std::cout<<"Serving HTTP @ http://"<