parent
eb5b203669
commit
b0f5377491
@ -5,7 +5,7 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-passwall2
|
||||
PKG_VERSION:=25.3.2
|
||||
PKG_VERSION:=25.4.1
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_CONFIG_DEPENDS:= \
|
||||
|
@ -176,7 +176,7 @@ function get_redir_log()
|
||||
local name = luci.http.formvalue("name")
|
||||
local file_path = "/tmp/etc/passwall2/acl/" .. id .. "/" .. name .. ".log"
|
||||
if nixio.fs.access(file_path) then
|
||||
local content = luci.sys.exec("cat '" .. file_path .. "'")
|
||||
local content = luci.sys.exec("tail -n 19999 '" .. file_path .. "'")
|
||||
content = content:gsub("\n", "<br />")
|
||||
luci.http.write(content)
|
||||
else
|
||||
@ -188,7 +188,7 @@ function get_socks_log()
|
||||
local name = luci.http.formvalue("name")
|
||||
local path = "/tmp/etc/passwall2/SOCKS_" .. name .. ".log"
|
||||
if nixio.fs.access(path) then
|
||||
local content = luci.sys.exec("cat ".. path)
|
||||
local content = luci.sys.exec("tail -n 5000 ".. path)
|
||||
content = content:gsub("\n", "<br />")
|
||||
luci.http.write(content)
|
||||
else
|
||||
|
@ -1,7 +1,7 @@
|
||||
local api = require "luci.passwall2.api"
|
||||
local appname = api.appname
|
||||
local datatypes = api.datatypes
|
||||
local has_singbox = api.finded_com("singbox")
|
||||
local has_singbox = api.finded_com("sing-box")
|
||||
local has_xray = api.finded_com("xray")
|
||||
|
||||
m = Map(appname)
|
||||
|
@ -3,7 +3,7 @@ local appname = api.appname
|
||||
local uci = api.uci
|
||||
local has_ss = api.is_finded("ss-redir")
|
||||
local has_ss_rust = api.is_finded("sslocal")
|
||||
local has_singbox = api.finded_com("singbox")
|
||||
local has_singbox = api.finded_com("sing-box")
|
||||
local has_xray = api.finded_com("xray")
|
||||
local has_hysteria2 = api.finded_com("hysteria")
|
||||
local ss_type = {}
|
||||
|
@ -11,7 +11,7 @@ end
|
||||
|
||||
local has_ss = api.is_finded("ss-redir")
|
||||
local has_ss_rust = api.is_finded("sslocal")
|
||||
local has_singbox = api.finded_com("singbox")
|
||||
local has_singbox = api.finded_com("sing-box")
|
||||
local has_xray = api.finded_com("xray")
|
||||
local has_hysteria2 = api.finded_com("hysteria")
|
||||
local ss_type = {}
|
||||
|
@ -1,7 +1,7 @@
|
||||
local api = require "luci.passwall2.api"
|
||||
local appname = api.appname
|
||||
local fs = api.fs
|
||||
local has_singbox = api.finded_com("singbox")
|
||||
local has_singbox = api.finded_com("sing-box")
|
||||
local has_xray = api.finded_com("xray")
|
||||
local has_fw3 = api.is_finded("fw3")
|
||||
local has_fw4 = api.is_finded("fw4")
|
||||
|
@ -8,7 +8,7 @@ if not arg[1] or not m:get(arg[1]) then
|
||||
luci.http.redirect(api.url())
|
||||
end
|
||||
|
||||
local has_singbox = api.finded_com("singbox")
|
||||
local has_singbox = api.finded_com("sing-box")
|
||||
local has_xray = api.finded_com("xray")
|
||||
|
||||
local nodes_table = {}
|
||||
|
@ -95,7 +95,7 @@ m.uci:foreach(appname, "socks", function(s)
|
||||
end)
|
||||
|
||||
-- 负载均衡列表
|
||||
local o = s:option(DynamicList, _n("balancing_node"), translate("Load balancing node list"), translate("Load balancing node list, <a target='_blank' href='https://toutyrater.github.io/routing/balance2.html'>document</a>"))
|
||||
local o = s:option(DynamicList, _n("balancing_node"), translate("Load balancing node list"), translate("Load balancing node list, <a target='_blank' href='https://xtls.github.io/config/routing.html#balancerobject'>document</a>"))
|
||||
o:depends({ [_n("protocol")] = "_balancing" })
|
||||
for k, v in pairs(nodes_table) do o:value(v.id, v.remark) end
|
||||
|
||||
@ -104,7 +104,8 @@ o:depends({ [_n("protocol")] = "_balancing" })
|
||||
o:value("random")
|
||||
o:value("roundRobin")
|
||||
o:value("leastPing")
|
||||
o.default = "leastPing"
|
||||
o:value("leastLoad")
|
||||
o.default = "leastLoad"
|
||||
|
||||
-- Fallback Node
|
||||
if api.compare_versions(xray_version, ">=", "1.8.10") then
|
||||
@ -133,6 +134,7 @@ end
|
||||
-- 探测地址
|
||||
local ucpu = s:option(Flag, _n("useCustomProbeUrl"), translate("Use Custome Probe URL"), translate("By default the built-in probe URL will be used, enable this option to use a custom probe URL."))
|
||||
ucpu:depends({ [_n("balancingStrategy")] = "leastPing" })
|
||||
ucpu:depends({ [_n("balancingStrategy")] = "leastLoad" })
|
||||
|
||||
local pu = s:option(Value, _n("probeUrl"), translate("Probe URL"))
|
||||
pu:depends({ [_n("useCustomProbeUrl")] = true })
|
||||
@ -148,8 +150,9 @@ pu.description = translate("The URL used to detect the connection status.")
|
||||
-- 探测间隔
|
||||
local pi = s:option(Value, _n("probeInterval"), translate("Probe Interval"))
|
||||
pi:depends({ [_n("balancingStrategy")] = "leastPing" })
|
||||
pi:depends({ [_n("balancingStrategy")] = "leastLoad" })
|
||||
pi.default = "1m"
|
||||
pi.description = translate("The interval between initiating probes. Every time this time elapses, a server status check is performed on a server. The time format is numbers + units, such as '10s', '2h45m', and the supported time units are <code>ns</code>, <code>us</code>, <code>ms</code>, <code>s</code>, <code>m</code>, <code>h</code>, which correspond to nanoseconds, microseconds, milliseconds, seconds, minutes, and hours, respectively.")
|
||||
pi.description = translate("The interval between initiating probes. The time format is numbers + units, such as '10s', '2h45m', and the supported time units are <code>ns</code>, <code>us</code>, <code>ms</code>, <code>s</code>, <code>m</code>, <code>h</code>, which correspond to nanoseconds, microseconds, milliseconds, seconds, minutes, and hours, respectively.")
|
||||
|
||||
if api.compare_versions(xray_version, ">=", "1.8.12") then
|
||||
ucpu:depends({ [_n("protocol")] = "_balancing" })
|
||||
@ -159,6 +162,12 @@ else
|
||||
pi:depends({ [_n("balancingStrategy")] = "leastPing" })
|
||||
end
|
||||
|
||||
o = s:option(Value, _n("expected"), translate("Preferred Node Count"))
|
||||
o:depends({ [_n("balancingStrategy")] = "leastLoad" })
|
||||
o.datatype = "uinteger"
|
||||
o.default = "2"
|
||||
o.description = translate("The load balancer selects the optimal number of nodes, and traffic is randomly distributed among them.")
|
||||
|
||||
|
||||
-- [[ 分流模块 ]]
|
||||
if #nodes_table > 0 then
|
||||
|
@ -2,7 +2,7 @@ local m, s = ...
|
||||
|
||||
local api = require "luci.passwall2.api"
|
||||
|
||||
local singbox_bin = api.finded_com("singbox")
|
||||
local singbox_bin = api.finded_com("sing-box")
|
||||
|
||||
if not singbox_bin then
|
||||
return
|
||||
@ -401,6 +401,10 @@ if singbox_tags:find("with_quic") then
|
||||
end
|
||||
|
||||
if singbox_tags:find("with_quic") then
|
||||
o = s:option(Value, _n("hysteria2_ports"), translate("Port hopping range"))
|
||||
o.description = translate("Format as 1000:2000 Multiple groups are separated by commas (,).")
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps"))
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
|
||||
|
@ -2,7 +2,7 @@ local m, s = ...
|
||||
|
||||
local api = require "luci.passwall2.api"
|
||||
|
||||
local singbox_bin = api.finded_com("singbox")
|
||||
local singbox_bin = api.finded_com("sing-box")
|
||||
|
||||
if not singbox_bin then
|
||||
return
|
||||
|
@ -23,7 +23,7 @@ _M.hysteria = {
|
||||
}
|
||||
}
|
||||
|
||||
_M.singbox = {
|
||||
_M["sing-box"] = {
|
||||
name = "Sing-Box",
|
||||
repo = "SagerNet/sing-box",
|
||||
get_url = gh_release_url,
|
||||
|
@ -149,7 +149,7 @@ local function start()
|
||||
bin = ln_run(api.get_app_path("xray"), "xray", "run -c " .. config_file, log_path)
|
||||
elseif type == "sing-box" then
|
||||
config = require(require_dir .. "util_sing-box").gen_config_server(user)
|
||||
bin = ln_run(api.get_app_path("singbox"), "sing-box", "run -c " .. config_file, log_path)
|
||||
bin = ln_run(api.get_app_path("sing-box"), "sing-box", "run -c " .. config_file, log_path)
|
||||
elseif type == "Hysteria2" then
|
||||
config = require(require_dir .. "util_hysteria2").gen_config_server(user)
|
||||
bin = ln_run(api.get_app_path("hysteria"), "hysteria", "-c " .. config_file .. " server", log_path)
|
||||
|
@ -8,7 +8,7 @@ local fs = api.fs
|
||||
local CACHE_PATH = api.CACHE_PATH
|
||||
local split = api.split
|
||||
|
||||
local local_version = api.get_app_version("singbox")
|
||||
local local_version = api.get_app_version("sing-box")
|
||||
local version_ge_1_11_0 = api.compare_versions(local_version:match("[^v]+"), ">=", "1.11.0")
|
||||
|
||||
local new_port
|
||||
@ -349,7 +349,17 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
end
|
||||
|
||||
if node.protocol == "hysteria2" then
|
||||
local server_ports = {}
|
||||
if node.hysteria2_ports then
|
||||
for range in node.hysteria2_ports:gmatch("([^,]+)") do
|
||||
if range:match("^%d+:%d+$") then
|
||||
table.insert(server_ports, range)
|
||||
end
|
||||
end
|
||||
end
|
||||
protocol_table = {
|
||||
server_ports = next(server_ports) and server_ports or nil,
|
||||
hop_interval = next(server_ports) and "30s" or nil,
|
||||
up_mbps = (node.hysteria2_up_mbps and tonumber(node.hysteria2_up_mbps)) and tonumber(node.hysteria2_up_mbps) or nil,
|
||||
down_mbps = (node.hysteria2_down_mbps and tonumber(node.hysteria2_down_mbps)) and tonumber(node.hysteria2_down_mbps) or nil,
|
||||
obfs = {
|
||||
|
@ -584,7 +584,8 @@ function gen_config(var)
|
||||
local inbounds = {}
|
||||
local outbounds = {}
|
||||
local routing = nil
|
||||
local observatory = nil
|
||||
local burstObservatory = nil
|
||||
local strategy = nil
|
||||
local COMMON = {}
|
||||
|
||||
local CACHE_TEXT_FILE = CACHE_PATH .. "/cache_" .. flag .. ".txt"
|
||||
@ -758,19 +759,33 @@ function gen_config(var)
|
||||
end
|
||||
end
|
||||
end
|
||||
if _node.balancingStrategy == "leastLoad" then
|
||||
strategy = {
|
||||
type = _node.balancingStrategy,
|
||||
settings = {
|
||||
expected = _node.expected and tonumber(_node.expected) and tonumber(_node.expected) or 2,
|
||||
maxRTT = "1s"
|
||||
}
|
||||
}
|
||||
else
|
||||
strategy = { type = _node.balancingStrategy or "random" }
|
||||
end
|
||||
table.insert(balancers, {
|
||||
tag = balancer_tag,
|
||||
selector = valid_nodes,
|
||||
fallbackTag = fallback_node_tag,
|
||||
strategy = { type = _node.balancingStrategy or "random" }
|
||||
strategy = strategy
|
||||
})
|
||||
if _node.balancingStrategy == "leastPing" or fallback_node_tag then
|
||||
if not observatory then
|
||||
observatory = {
|
||||
if _node.balancingStrategy == "leastPing" or _node.balancingStrategy == "leastLoad" or fallback_node_tag then
|
||||
if not burstObservatory then
|
||||
burstObservatory = {
|
||||
subjectSelector = { "blc-" },
|
||||
probeUrl = _node.useCustomProbeUrl and _node.probeUrl or nil,
|
||||
probeInterval = _node.probeInterval or "1m",
|
||||
enableConcurrency = true
|
||||
pingConfig = {
|
||||
destination = _node.useCustomProbeUrl and _node.probeUrl or nil,
|
||||
interval = _node.probeInterval or "1m",
|
||||
sampling = 3,
|
||||
timeout = "5s"
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
@ -1483,7 +1498,7 @@ function gen_config(var)
|
||||
-- 传出连接
|
||||
outbounds = outbounds,
|
||||
-- 连接观测
|
||||
observatory = observatory,
|
||||
burstObservatory = burstObservatory,
|
||||
-- 路由
|
||||
routing = routing,
|
||||
-- 本地策略
|
||||
|
@ -10,7 +10,7 @@ local hysteria2_type = map:get("@global_subscribe[0]", "hysteria2_type") or "sin
|
||||
-%>
|
||||
<script src="<%=resource%>/qrcode.min.js"></script>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
let has_singbox = "<%=api.finded_com("singbox")%>"
|
||||
let has_singbox = "<%=api.finded_com("sing-box")%>"
|
||||
let has_xray = "<%=api.finded_com("xray")%>"
|
||||
let has_hysteria2 = "<%=api.finded_com("hysteria")%>"
|
||||
let ss_type = "<%=ss_type%>"
|
||||
|
@ -313,82 +313,84 @@ table td, .table .td {
|
||||
}
|
||||
|
||||
/* 自动Ping */
|
||||
if (auto_detection_time == "icmp" || auto_detection_time == "tcping") {
|
||||
var nodes = [];
|
||||
const ping_value = document.getElementsByClassName(auto_detection_time == "tcping" ? 'tcping_value' : 'ping_value');
|
||||
for (var i = 0; i < ping_value.length; i++) {
|
||||
var cbi_id = ping_value[i].getAttribute("cbiid");
|
||||
var full = get_address_full(cbi_id);
|
||||
if (full != null) {
|
||||
var flag = false;
|
||||
//当有多个相同地址和端口时合在一起
|
||||
for (var j = 0; j < nodes.length; j++) {
|
||||
if (nodes[j].address == full.address && nodes[j].port == full.port) {
|
||||
nodes[j].indexs = nodes[j].indexs + "," + i;
|
||||
flag = true;
|
||||
break;
|
||||
function pingAllNodes() {
|
||||
if (auto_detection_time == "icmp" || auto_detection_time == "tcping") {
|
||||
var nodes = [];
|
||||
const ping_value = document.getElementsByClassName(auto_detection_time == "tcping" ? 'tcping_value' : 'ping_value');
|
||||
for (var i = 0; i < ping_value.length; i++) {
|
||||
var cbi_id = ping_value[i].getAttribute("cbiid");
|
||||
var full = get_address_full(cbi_id);
|
||||
if (full != null) {
|
||||
var flag = false;
|
||||
//当有多个相同地址和端口时合在一起
|
||||
for (var j = 0; j < nodes.length; j++) {
|
||||
if (nodes[j].address == full.address && nodes[j].port == full.port) {
|
||||
nodes[j].indexs = nodes[j].indexs + "," + i;
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (flag)
|
||||
continue;
|
||||
nodes.push({
|
||||
indexs: i + "",
|
||||
address: full.address,
|
||||
port: full.port
|
||||
});
|
||||
}
|
||||
if (flag)
|
||||
continue;
|
||||
nodes.push({
|
||||
indexs: i + "",
|
||||
address: full.address,
|
||||
port: full.port
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const _xhr = (index) => {
|
||||
return new Promise((res) => {
|
||||
const dom = nodes[index];
|
||||
if (!dom) res()
|
||||
ajax.post('<%=api.url("ping_node")%>', {
|
||||
index: dom.indexs,
|
||||
address: dom.address,
|
||||
port: dom.port,
|
||||
type: auto_detection_time
|
||||
},
|
||||
function(x, result) {
|
||||
if (x && x.status == 200) {
|
||||
var strs = dom.indexs.split(",");
|
||||
for (var i = 0; i < strs.length; i++) {
|
||||
if (result.ping == null || result.ping.trim() == "") {
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>";
|
||||
} else {
|
||||
var ping = parseInt(result.ping);
|
||||
if (ping < 100)
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:green'>" + result.ping + " ms" + "</font>";
|
||||
else if (ping < 200)
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:#fb9a05'>" + result.ping + " ms" + "</font>";
|
||||
else if (ping >= 200)
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:red'>" + result.ping + " ms" + "</font>";
|
||||
|
||||
const _xhr = (index) => {
|
||||
return new Promise((res) => {
|
||||
const dom = nodes[index];
|
||||
if (!dom) res()
|
||||
ajax.post('<%=api.url("ping_node")%>', {
|
||||
index: dom.indexs,
|
||||
address: dom.address,
|
||||
port: dom.port,
|
||||
type: auto_detection_time
|
||||
},
|
||||
function(x, result) {
|
||||
if (x && x.status == 200) {
|
||||
var strs = dom.indexs.split(",");
|
||||
for (var i = 0; i < strs.length; i++) {
|
||||
if (result.ping == null || result.ping.trim() == "") {
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>";
|
||||
} else {
|
||||
var ping = parseInt(result.ping);
|
||||
if (ping < 100)
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:green'>" + result.ping + " ms" + "</font>";
|
||||
else if (ping < 200)
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:#fb9a05'>" + result.ping + " ms" + "</font>";
|
||||
else if (ping >= 200)
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:red'>" + result.ping + " ms" + "</font>";
|
||||
}
|
||||
}
|
||||
}
|
||||
res();
|
||||
},
|
||||
5000,
|
||||
function(x) {
|
||||
var strs = dom.indexs.split(",");
|
||||
for (var i = 0; i < strs.length; i++) {
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>";
|
||||
}
|
||||
res();
|
||||
}
|
||||
res();
|
||||
},
|
||||
5000,
|
||||
function(x) {
|
||||
var strs = dom.indexs.split(",");
|
||||
for (var i = 0; i < strs.length; i++) {
|
||||
ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>";
|
||||
}
|
||||
res();
|
||||
}
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
let task = -1;
|
||||
const thread = () => {
|
||||
task = task + 1
|
||||
if (nodes[task]) {
|
||||
_xhr(task).then(thread);
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
let task = -1;
|
||||
const thread = () => {
|
||||
task = task + 1
|
||||
if (nodes[task]) {
|
||||
_xhr(task).then(thread);
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < 20; i++) {
|
||||
thread()
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < 20; i++) {
|
||||
thread()
|
||||
}
|
||||
}
|
||||
|
||||
@ -445,6 +447,14 @@ table td, .table .td {
|
||||
}
|
||||
document.getElementById("div_node_count").innerHTML = "<div style='margin-top:5px'>" + str + "</div>";
|
||||
}
|
||||
|
||||
//UI渲染完成后再自动Ping
|
||||
window.onload = function () {
|
||||
setTimeout(function () {
|
||||
pingAllNodes();
|
||||
}, 800);
|
||||
};
|
||||
|
||||
//]]>
|
||||
</script>
|
||||
|
||||
|
@ -355,8 +355,14 @@ msgstr "用于检测连接状态的网址。"
|
||||
msgid "Probe Interval"
|
||||
msgstr "探测间隔"
|
||||
|
||||
msgid "The interval between initiating probes. Every time this time elapses, a server status check is performed on a server. The time format is numbers + units, such as '10s', '2h45m', and the supported time units are <code>ns</code>, <code>us</code>, <code>ms</code>, <code>s</code>, <code>m</code>, <code>h</code>, which correspond to nanoseconds, microseconds, milliseconds, seconds, minutes, and hours, respectively."
|
||||
msgstr "发起探测的间隔。每经过这个时间,就会对一个服务器进行服务器状态检测。时间格式为数字+单位,比如<code>"10s"</code>, <code>"2h45m"</code>,支持的时间单位有 <code>ns</code>,<code>us</code>,<code>ms</code>,<code>s</code>,<code>m</code>,<code>h</code>,分别对应纳秒、微秒、毫秒、秒、分、时。"
|
||||
msgid "The interval between initiating probes. The time format is numbers + units, such as '10s', '2h45m', and the supported time units are <code>ns</code>, <code>us</code>, <code>ms</code>, <code>s</code>, <code>m</code>, <code>h</code>, which correspond to nanoseconds, microseconds, milliseconds, seconds, minutes, and hours, respectively."
|
||||
msgstr "发起探测的间隔。时间格式为数字+单位,比如<code>"10s"</code>, <code>"2h45m"</code>,支持的时间单位有 <code>ns</code>,<code>us</code>,<code>ms</code>,<code>s</code>,<code>m</code>,<code>h</code>,分别对应纳秒、微秒、毫秒、秒、分、时。"
|
||||
|
||||
msgid "Preferred Node Count"
|
||||
msgstr "优选节点数量"
|
||||
|
||||
msgid "The load balancer selects the optimal number of nodes, and traffic is randomly distributed among them."
|
||||
msgstr "负载均衡器选出最优节点的个数,流量将在这几个节点中随机分配。"
|
||||
|
||||
msgid "Shunt"
|
||||
msgstr "分流"
|
||||
@ -406,8 +412,8 @@ msgstr "IPOnDemand:当匹配时碰到任何基于 IP 的规则,将域名立
|
||||
msgid "Load balancing node list"
|
||||
msgstr "负载均衡节点列表"
|
||||
|
||||
msgid "Load balancing node list, <a target='_blank' href='https://toutyrater.github.io/routing/balance2.html'>document</a>"
|
||||
msgstr "负载均衡节点列表,<a target='_blank' href='https://toutyrater.github.io/routing/balance2.html'>文档原理</a>"
|
||||
msgid "Load balancing node list, <a target='_blank' href='https://xtls.github.io/config/routing.html#balancerobject'>document</a>"
|
||||
msgstr "负载均衡节点列表,<a target='_blank' href='https://xtls.github.io/config/routing.html#balancerobject'>文档原理</a>"
|
||||
|
||||
msgid "From Share URL"
|
||||
msgstr "导入分享URL"
|
||||
@ -1677,3 +1683,9 @@ msgstr "中断现有连接"
|
||||
|
||||
msgid "Interrupt existing connections when the selected outbound has changed."
|
||||
msgstr "当选择的出站发生变化时中断现有连接。"
|
||||
|
||||
msgid "Port hopping range"
|
||||
msgstr "端口跳跃范围"
|
||||
|
||||
msgid "Format as 1000:2000 Multiple groups are separated by commas (,)."
|
||||
msgstr "格式为:1000:2000 多组时用逗号(,)隔开。"
|
||||
|
@ -8,7 +8,7 @@ server_port=$4
|
||||
probe_file="/tmp/etc/passwall2/haproxy/Probe_URL"
|
||||
probeUrl="https://www.google.com/generate_204"
|
||||
if [ -f "$probe_file" ]; then
|
||||
firstLine=$(head -n 1 "$probe_file" | tr -d ' \t')
|
||||
firstLine=$(head -n 1 "$probe_file" | tr -d ' \t\n')
|
||||
[ -n "$firstLine" ] && probeUrl="$firstLine"
|
||||
fi
|
||||
|
||||
|
@ -23,7 +23,7 @@ uci:revert(appname)
|
||||
|
||||
local has_ss = api.is_finded("ss-redir")
|
||||
local has_ss_rust = api.is_finded("sslocal")
|
||||
local has_singbox = api.finded_com("singbox")
|
||||
local has_singbox = api.finded_com("sing-box")
|
||||
local has_xray = api.finded_com("xray")
|
||||
local has_hysteria2 = api.finded_com("hysteria")
|
||||
local allowInsecure_default = true
|
||||
@ -182,6 +182,11 @@ do
|
||||
if true then
|
||||
local i = 0
|
||||
local option = "lbss"
|
||||
local function is_ip_port(str)
|
||||
if type(str) ~= "string" then return false end
|
||||
local ip, port = str:match("^([%d%.]+):(%d+)$")
|
||||
return ip and datatypes.ipaddr(ip) and tonumber(port) and tonumber(port) <= 65535
|
||||
end
|
||||
uci:foreach(appname, "haproxy_config", function(t)
|
||||
i = i + 1
|
||||
local node_id = t[option]
|
||||
@ -191,11 +196,17 @@ do
|
||||
remarks = "HAProxy负载均衡节点列表[" .. i .. "]",
|
||||
currentNode = node_id and uci:get_all(appname, node_id) or nil,
|
||||
set = function(o, server)
|
||||
uci:set(appname, t[".name"], option, server)
|
||||
o.newNodeId = server
|
||||
-- 如果当前 lbss 值不是 ip:port 格式,才进行修改
|
||||
if not is_ip_port(t[option]) then
|
||||
uci:set(appname, t[".name"], option, server)
|
||||
o.newNodeId = server
|
||||
end
|
||||
end,
|
||||
delete = function(o)
|
||||
uci:delete(appname, t[".name"])
|
||||
-- 如果当前 lbss 值不是 ip:port 格式,才进行删除
|
||||
if not is_ip_port(t[option]) then
|
||||
uci:delete(appname, t[".name"])
|
||||
end
|
||||
end
|
||||
}
|
||||
end)
|
||||
@ -1294,19 +1305,21 @@ local function processData(szType, content, add_mode, add_from)
|
||||
end
|
||||
|
||||
local function curl(url, file, ua, mode)
|
||||
local curl_args = api.clone(api.curl_args)
|
||||
local curl_args = {
|
||||
"-skL", "-w %{http_code}", "--retry 3", "--connect-timeout 3"
|
||||
}
|
||||
if ua and ua ~= "" and ua ~= "curl" then
|
||||
table.insert(curl_args, '--user-agent "' .. ua .. '"')
|
||||
curl_args[#curl_args + 1] = '--user-agent "' .. ua .. '"'
|
||||
end
|
||||
local return_code
|
||||
local return_code, result
|
||||
if mode == "direct" then
|
||||
return_code = api.curl_direct(url, file, curl_args)
|
||||
return_code, result = api.curl_direct(url, file, curl_args)
|
||||
elseif mode == "proxy" then
|
||||
return_code = api.curl_proxy(url, file, curl_args)
|
||||
return_code, result = api.curl_proxy(url, file, curl_args)
|
||||
else
|
||||
return_code = api.curl_auto(url, file, curl_args)
|
||||
return_code, result = api.curl_auto(url, file, curl_args)
|
||||
end
|
||||
return return_code
|
||||
return tonumber(result)
|
||||
end
|
||||
|
||||
local function truncate_nodes(add_from)
|
||||
@ -1630,7 +1643,7 @@ local function parse_link(raw, add_mode, add_from, cfgid)
|
||||
log('成功解析【' .. add_from .. '】节点数量: ' .. #node_list)
|
||||
else
|
||||
if add_mode == "2" then
|
||||
log('获取到的【' .. add_from .. '】订阅内容为空,可能是订阅地址失效,或是网络问题,请请检测。')
|
||||
log('获取到的【' .. add_from .. '】订阅内容为空,可能是订阅地址无效,或是网络问题,请诊断!')
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1705,23 +1718,27 @@ local execute = function()
|
||||
local result = (not access_mode) and "自动" or (access_mode == "direct" and "直连访问" or (access_mode == "proxy" and "通过代理" or "自动"))
|
||||
log('正在订阅:【' .. remark .. '】' .. url .. ' [' .. result .. ']')
|
||||
local tmp_file = "/tmp/" .. cfgid
|
||||
local raw = curl(url, tmp_file, ua, access_mode)
|
||||
if raw == 0 then
|
||||
local f = io.open(tmp_file, "r")
|
||||
local stdout = f:read("*all")
|
||||
f:close()
|
||||
raw = trim(stdout)
|
||||
local old_md5 = value.md5 or ""
|
||||
local new_md5 = luci.sys.exec("[ -f " .. tmp_file .. " ] && md5sum " .. tmp_file .. " | awk '{print $1}' || echo 0"):gsub("\n", "")
|
||||
os.remove(tmp_file)
|
||||
if old_md5 == new_md5 then
|
||||
log('订阅:【' .. remark .. '】没有变化,无需更新。')
|
||||
else
|
||||
parse_link(raw, "2", remark, cfgid)
|
||||
uci:set(appname, cfgid, "md5", new_md5)
|
||||
end
|
||||
else
|
||||
value.http_code = curl(url, tmp_file, ua, access_mode)
|
||||
if value.http_code ~= 200 then
|
||||
fail_list[#fail_list + 1] = value
|
||||
else
|
||||
if luci.sys.call("[ -f " .. tmp_file .. " ] && sed -i -e '/^[ \t]*$/d' -e '/^[ \t]*\r$/d' " .. tmp_file) == 0 then
|
||||
local f = io.open(tmp_file, "r")
|
||||
local stdout = f:read("*all")
|
||||
f:close()
|
||||
local raw_data = trim(stdout)
|
||||
local old_md5 = value.md5 or ""
|
||||
local new_md5 = luci.sys.exec("md5sum " .. tmp_file .. " 2>/dev/null | awk '{print $1}'"):gsub("\n", "")
|
||||
os.remove(tmp_file)
|
||||
if old_md5 == new_md5 then
|
||||
log('订阅:【' .. remark .. '】没有变化,无需更新。')
|
||||
else
|
||||
parse_link(raw_data, "2", remark, cfgid)
|
||||
uci:set(appname, cfgid, "md5", new_md5)
|
||||
end
|
||||
else
|
||||
fail_list[#fail_list + 1] = value
|
||||
end
|
||||
end
|
||||
allowInsecure_default = true
|
||||
filter_keyword_mode_default = uci:get(appname, "@global_subscribe[0]", "filter_keyword_mode") or "0"
|
||||
@ -1736,7 +1753,7 @@ local execute = function()
|
||||
|
||||
if #fail_list > 0 then
|
||||
for index, value in ipairs(fail_list) do
|
||||
log(string.format('【%s】订阅失败,可能是订阅地址失效,或是网络问题,请诊断!', value.remark))
|
||||
log(string.format('【%s】订阅失败,可能是订阅地址无效,或是网络问题,请诊断![%s]', value.remark, tostring(value.http_code)))
|
||||
end
|
||||
end
|
||||
update_node(0)
|
||||
|
Loading…
Reference in New Issue
Block a user