parent
eb5b203669
commit
b0f5377491
@ -5,7 +5,7 @@
|
|||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=luci-app-passwall2
|
PKG_NAME:=luci-app-passwall2
|
||||||
PKG_VERSION:=25.3.2
|
PKG_VERSION:=25.4.1
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=1
|
||||||
|
|
||||||
PKG_CONFIG_DEPENDS:= \
|
PKG_CONFIG_DEPENDS:= \
|
||||||
|
@ -176,7 +176,7 @@ function get_redir_log()
|
|||||||
local name = luci.http.formvalue("name")
|
local name = luci.http.formvalue("name")
|
||||||
local file_path = "/tmp/etc/passwall2/acl/" .. id .. "/" .. name .. ".log"
|
local file_path = "/tmp/etc/passwall2/acl/" .. id .. "/" .. name .. ".log"
|
||||||
if nixio.fs.access(file_path) then
|
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 />")
|
content = content:gsub("\n", "<br />")
|
||||||
luci.http.write(content)
|
luci.http.write(content)
|
||||||
else
|
else
|
||||||
@ -188,7 +188,7 @@ function get_socks_log()
|
|||||||
local name = luci.http.formvalue("name")
|
local name = luci.http.formvalue("name")
|
||||||
local path = "/tmp/etc/passwall2/SOCKS_" .. name .. ".log"
|
local path = "/tmp/etc/passwall2/SOCKS_" .. name .. ".log"
|
||||||
if nixio.fs.access(path) then
|
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 />")
|
content = content:gsub("\n", "<br />")
|
||||||
luci.http.write(content)
|
luci.http.write(content)
|
||||||
else
|
else
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
local api = require "luci.passwall2.api"
|
local api = require "luci.passwall2.api"
|
||||||
local appname = api.appname
|
local appname = api.appname
|
||||||
local datatypes = api.datatypes
|
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")
|
local has_xray = api.finded_com("xray")
|
||||||
|
|
||||||
m = Map(appname)
|
m = Map(appname)
|
||||||
|
@ -3,7 +3,7 @@ local appname = api.appname
|
|||||||
local uci = api.uci
|
local uci = api.uci
|
||||||
local has_ss = api.is_finded("ss-redir")
|
local has_ss = api.is_finded("ss-redir")
|
||||||
local has_ss_rust = api.is_finded("sslocal")
|
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_xray = api.finded_com("xray")
|
||||||
local has_hysteria2 = api.finded_com("hysteria")
|
local has_hysteria2 = api.finded_com("hysteria")
|
||||||
local ss_type = {}
|
local ss_type = {}
|
||||||
|
@ -11,7 +11,7 @@ end
|
|||||||
|
|
||||||
local has_ss = api.is_finded("ss-redir")
|
local has_ss = api.is_finded("ss-redir")
|
||||||
local has_ss_rust = api.is_finded("sslocal")
|
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_xray = api.finded_com("xray")
|
||||||
local has_hysteria2 = api.finded_com("hysteria")
|
local has_hysteria2 = api.finded_com("hysteria")
|
||||||
local ss_type = {}
|
local ss_type = {}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
local api = require "luci.passwall2.api"
|
local api = require "luci.passwall2.api"
|
||||||
local appname = api.appname
|
local appname = api.appname
|
||||||
local fs = api.fs
|
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_xray = api.finded_com("xray")
|
||||||
local has_fw3 = api.is_finded("fw3")
|
local has_fw3 = api.is_finded("fw3")
|
||||||
local has_fw4 = api.is_finded("fw4")
|
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())
|
luci.http.redirect(api.url())
|
||||||
end
|
end
|
||||||
|
|
||||||
local has_singbox = api.finded_com("singbox")
|
local has_singbox = api.finded_com("sing-box")
|
||||||
local has_xray = api.finded_com("xray")
|
local has_xray = api.finded_com("xray")
|
||||||
|
|
||||||
local nodes_table = {}
|
local nodes_table = {}
|
||||||
|
@ -95,7 +95,7 @@ m.uci:foreach(appname, "socks", function(s)
|
|||||||
end)
|
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" })
|
o:depends({ [_n("protocol")] = "_balancing" })
|
||||||
for k, v in pairs(nodes_table) do o:value(v.id, v.remark) end
|
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("random")
|
||||||
o:value("roundRobin")
|
o:value("roundRobin")
|
||||||
o:value("leastPing")
|
o:value("leastPing")
|
||||||
o.default = "leastPing"
|
o:value("leastLoad")
|
||||||
|
o.default = "leastLoad"
|
||||||
|
|
||||||
-- Fallback Node
|
-- Fallback Node
|
||||||
if api.compare_versions(xray_version, ">=", "1.8.10") then
|
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."))
|
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")] = "leastPing" })
|
||||||
|
ucpu:depends({ [_n("balancingStrategy")] = "leastLoad" })
|
||||||
|
|
||||||
local pu = s:option(Value, _n("probeUrl"), translate("Probe URL"))
|
local pu = s:option(Value, _n("probeUrl"), translate("Probe URL"))
|
||||||
pu:depends({ [_n("useCustomProbeUrl")] = true })
|
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"))
|
local pi = s:option(Value, _n("probeInterval"), translate("Probe Interval"))
|
||||||
pi:depends({ [_n("balancingStrategy")] = "leastPing" })
|
pi:depends({ [_n("balancingStrategy")] = "leastPing" })
|
||||||
|
pi:depends({ [_n("balancingStrategy")] = "leastLoad" })
|
||||||
pi.default = "1m"
|
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
|
if api.compare_versions(xray_version, ">=", "1.8.12") then
|
||||||
ucpu:depends({ [_n("protocol")] = "_balancing" })
|
ucpu:depends({ [_n("protocol")] = "_balancing" })
|
||||||
@ -159,6 +162,12 @@ else
|
|||||||
pi:depends({ [_n("balancingStrategy")] = "leastPing" })
|
pi:depends({ [_n("balancingStrategy")] = "leastPing" })
|
||||||
end
|
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
|
if #nodes_table > 0 then
|
||||||
|
@ -2,7 +2,7 @@ local m, s = ...
|
|||||||
|
|
||||||
local api = require "luci.passwall2.api"
|
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
|
if not singbox_bin then
|
||||||
return
|
return
|
||||||
@ -401,6 +401,10 @@ if singbox_tags:find("with_quic") then
|
|||||||
end
|
end
|
||||||
|
|
||||||
if singbox_tags:find("with_quic") then
|
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 = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps"))
|
||||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ local m, s = ...
|
|||||||
|
|
||||||
local api = require "luci.passwall2.api"
|
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
|
if not singbox_bin then
|
||||||
return
|
return
|
||||||
|
@ -23,7 +23,7 @@ _M.hysteria = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_M.singbox = {
|
_M["sing-box"] = {
|
||||||
name = "Sing-Box",
|
name = "Sing-Box",
|
||||||
repo = "SagerNet/sing-box",
|
repo = "SagerNet/sing-box",
|
||||||
get_url = gh_release_url,
|
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)
|
bin = ln_run(api.get_app_path("xray"), "xray", "run -c " .. config_file, log_path)
|
||||||
elseif type == "sing-box" then
|
elseif type == "sing-box" then
|
||||||
config = require(require_dir .. "util_sing-box").gen_config_server(user)
|
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
|
elseif type == "Hysteria2" then
|
||||||
config = require(require_dir .. "util_hysteria2").gen_config_server(user)
|
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)
|
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 CACHE_PATH = api.CACHE_PATH
|
||||||
local split = api.split
|
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 version_ge_1_11_0 = api.compare_versions(local_version:match("[^v]+"), ">=", "1.11.0")
|
||||||
|
|
||||||
local new_port
|
local new_port
|
||||||
@ -349,7 +349,17 @@ function gen_outbound(flag, node, tag, proxy_table)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if node.protocol == "hysteria2" then
|
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 = {
|
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,
|
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,
|
down_mbps = (node.hysteria2_down_mbps and tonumber(node.hysteria2_down_mbps)) and tonumber(node.hysteria2_down_mbps) or nil,
|
||||||
obfs = {
|
obfs = {
|
||||||
|
@ -584,7 +584,8 @@ function gen_config(var)
|
|||||||
local inbounds = {}
|
local inbounds = {}
|
||||||
local outbounds = {}
|
local outbounds = {}
|
||||||
local routing = nil
|
local routing = nil
|
||||||
local observatory = nil
|
local burstObservatory = nil
|
||||||
|
local strategy = nil
|
||||||
local COMMON = {}
|
local COMMON = {}
|
||||||
|
|
||||||
local CACHE_TEXT_FILE = CACHE_PATH .. "/cache_" .. flag .. ".txt"
|
local CACHE_TEXT_FILE = CACHE_PATH .. "/cache_" .. flag .. ".txt"
|
||||||
@ -758,19 +759,33 @@ function gen_config(var)
|
|||||||
end
|
end
|
||||||
end
|
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, {
|
table.insert(balancers, {
|
||||||
tag = balancer_tag,
|
tag = balancer_tag,
|
||||||
selector = valid_nodes,
|
selector = valid_nodes,
|
||||||
fallbackTag = fallback_node_tag,
|
fallbackTag = fallback_node_tag,
|
||||||
strategy = { type = _node.balancingStrategy or "random" }
|
strategy = strategy
|
||||||
})
|
})
|
||||||
if _node.balancingStrategy == "leastPing" or fallback_node_tag then
|
if _node.balancingStrategy == "leastPing" or _node.balancingStrategy == "leastLoad" or fallback_node_tag then
|
||||||
if not observatory then
|
if not burstObservatory then
|
||||||
observatory = {
|
burstObservatory = {
|
||||||
subjectSelector = { "blc-" },
|
subjectSelector = { "blc-" },
|
||||||
probeUrl = _node.useCustomProbeUrl and _node.probeUrl or nil,
|
pingConfig = {
|
||||||
probeInterval = _node.probeInterval or "1m",
|
destination = _node.useCustomProbeUrl and _node.probeUrl or nil,
|
||||||
enableConcurrency = true
|
interval = _node.probeInterval or "1m",
|
||||||
|
sampling = 3,
|
||||||
|
timeout = "5s"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1483,7 +1498,7 @@ function gen_config(var)
|
|||||||
-- 传出连接
|
-- 传出连接
|
||||||
outbounds = outbounds,
|
outbounds = outbounds,
|
||||||
-- 连接观测
|
-- 连接观测
|
||||||
observatory = observatory,
|
burstObservatory = burstObservatory,
|
||||||
-- 路由
|
-- 路由
|
||||||
routing = routing,
|
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 src="<%=resource%>/qrcode.min.js"></script>
|
||||||
<script type="text/javascript">//<![CDATA[
|
<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_xray = "<%=api.finded_com("xray")%>"
|
||||||
let has_hysteria2 = "<%=api.finded_com("hysteria")%>"
|
let has_hysteria2 = "<%=api.finded_com("hysteria")%>"
|
||||||
let ss_type = "<%=ss_type%>"
|
let ss_type = "<%=ss_type%>"
|
||||||
|
@ -313,82 +313,84 @@ table td, .table .td {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 自动Ping */
|
/* 自动Ping */
|
||||||
if (auto_detection_time == "icmp" || auto_detection_time == "tcping") {
|
function pingAllNodes() {
|
||||||
var nodes = [];
|
if (auto_detection_time == "icmp" || auto_detection_time == "tcping") {
|
||||||
const ping_value = document.getElementsByClassName(auto_detection_time == "tcping" ? 'tcping_value' : 'ping_value');
|
var nodes = [];
|
||||||
for (var i = 0; i < ping_value.length; i++) {
|
const ping_value = document.getElementsByClassName(auto_detection_time == "tcping" ? 'tcping_value' : 'ping_value');
|
||||||
var cbi_id = ping_value[i].getAttribute("cbiid");
|
for (var i = 0; i < ping_value.length; i++) {
|
||||||
var full = get_address_full(cbi_id);
|
var cbi_id = ping_value[i].getAttribute("cbiid");
|
||||||
if (full != null) {
|
var full = get_address_full(cbi_id);
|
||||||
var flag = false;
|
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) {
|
for (var j = 0; j < nodes.length; j++) {
|
||||||
nodes[j].indexs = nodes[j].indexs + "," + i;
|
if (nodes[j].address == full.address && nodes[j].port == full.port) {
|
||||||
flag = true;
|
nodes[j].indexs = nodes[j].indexs + "," + i;
|
||||||
break;
|
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) => {
|
const _xhr = (index) => {
|
||||||
return new Promise((res) => {
|
return new Promise((res) => {
|
||||||
const dom = nodes[index];
|
const dom = nodes[index];
|
||||||
if (!dom) res()
|
if (!dom) res()
|
||||||
ajax.post('<%=api.url("ping_node")%>', {
|
ajax.post('<%=api.url("ping_node")%>', {
|
||||||
index: dom.indexs,
|
index: dom.indexs,
|
||||||
address: dom.address,
|
address: dom.address,
|
||||||
port: dom.port,
|
port: dom.port,
|
||||||
type: auto_detection_time
|
type: auto_detection_time
|
||||||
},
|
},
|
||||||
function(x, result) {
|
function(x, result) {
|
||||||
if (x && x.status == 200) {
|
if (x && x.status == 200) {
|
||||||
var strs = dom.indexs.split(",");
|
var strs = dom.indexs.split(",");
|
||||||
for (var i = 0; i < strs.length; i++) {
|
for (var i = 0; i < strs.length; i++) {
|
||||||
if (result.ping == null || result.ping.trim() == "") {
|
if (result.ping == null || result.ping.trim() == "") {
|
||||||
ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>";
|
ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>";
|
||||||
} else {
|
} else {
|
||||||
var ping = parseInt(result.ping);
|
var ping = parseInt(result.ping);
|
||||||
if (ping < 100)
|
if (ping < 100)
|
||||||
ping_value[strs[i]].innerHTML = "<font style='color:green'>" + result.ping + " ms" + "</font>";
|
ping_value[strs[i]].innerHTML = "<font style='color:green'>" + result.ping + " ms" + "</font>";
|
||||||
else if (ping < 200)
|
else if (ping < 200)
|
||||||
ping_value[strs[i]].innerHTML = "<font style='color:#fb9a05'>" + result.ping + " ms" + "</font>";
|
ping_value[strs[i]].innerHTML = "<font style='color:#fb9a05'>" + result.ping + " ms" + "</font>";
|
||||||
else if (ping >= 200)
|
else if (ping >= 200)
|
||||||
ping_value[strs[i]].innerHTML = "<font style='color:red'>" + result.ping + " ms" + "</font>";
|
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(",");
|
let task = -1;
|
||||||
for (var i = 0; i < strs.length; i++) {
|
const thread = () => {
|
||||||
ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>";
|
task = task + 1
|
||||||
}
|
if (nodes[task]) {
|
||||||
res();
|
_xhr(task).then(thread);
|
||||||
}
|
}
|
||||||
);
|
}
|
||||||
})
|
for (let i = 0; i < 20; i++) {
|
||||||
}
|
thread()
|
||||||
|
|
||||||
let task = -1;
|
|
||||||
const thread = () => {
|
|
||||||
task = task + 1
|
|
||||||
if (nodes[task]) {
|
|
||||||
_xhr(task).then(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>";
|
document.getElementById("div_node_count").innerHTML = "<div style='margin-top:5px'>" + str + "</div>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//UI渲染完成后再自动Ping
|
||||||
|
window.onload = function () {
|
||||||
|
setTimeout(function () {
|
||||||
|
pingAllNodes();
|
||||||
|
}, 800);
|
||||||
|
};
|
||||||
|
|
||||||
//]]>
|
//]]>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -355,8 +355,14 @@ msgstr "用于检测连接状态的网址。"
|
|||||||
msgid "Probe Interval"
|
msgid "Probe Interval"
|
||||||
msgstr "探测间隔"
|
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."
|
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>,分别对应纳秒、微秒、毫秒、秒、分、时。"
|
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"
|
msgid "Shunt"
|
||||||
msgstr "分流"
|
msgstr "分流"
|
||||||
@ -406,8 +412,8 @@ msgstr "IPOnDemand:当匹配时碰到任何基于 IP 的规则,将域名立
|
|||||||
msgid "Load balancing node list"
|
msgid "Load balancing node list"
|
||||||
msgstr "负载均衡节点列表"
|
msgstr "负载均衡节点列表"
|
||||||
|
|
||||||
msgid "Load balancing node list, <a target='_blank' href='https://toutyrater.github.io/routing/balance2.html'>document</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://toutyrater.github.io/routing/balance2.html'>文档原理</a>"
|
msgstr "负载均衡节点列表,<a target='_blank' href='https://xtls.github.io/config/routing.html#balancerobject'>文档原理</a>"
|
||||||
|
|
||||||
msgid "From Share URL"
|
msgid "From Share URL"
|
||||||
msgstr "导入分享URL"
|
msgstr "导入分享URL"
|
||||||
@ -1677,3 +1683,9 @@ msgstr "中断现有连接"
|
|||||||
|
|
||||||
msgid "Interrupt existing connections when the selected outbound has changed."
|
msgid "Interrupt existing connections when the selected outbound has changed."
|
||||||
msgstr "当选择的出站发生变化时中断现有连接。"
|
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"
|
probe_file="/tmp/etc/passwall2/haproxy/Probe_URL"
|
||||||
probeUrl="https://www.google.com/generate_204"
|
probeUrl="https://www.google.com/generate_204"
|
||||||
if [ -f "$probe_file" ]; then
|
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"
|
[ -n "$firstLine" ] && probeUrl="$firstLine"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ uci:revert(appname)
|
|||||||
|
|
||||||
local has_ss = api.is_finded("ss-redir")
|
local has_ss = api.is_finded("ss-redir")
|
||||||
local has_ss_rust = api.is_finded("sslocal")
|
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_xray = api.finded_com("xray")
|
||||||
local has_hysteria2 = api.finded_com("hysteria")
|
local has_hysteria2 = api.finded_com("hysteria")
|
||||||
local allowInsecure_default = true
|
local allowInsecure_default = true
|
||||||
@ -182,6 +182,11 @@ do
|
|||||||
if true then
|
if true then
|
||||||
local i = 0
|
local i = 0
|
||||||
local option = "lbss"
|
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)
|
uci:foreach(appname, "haproxy_config", function(t)
|
||||||
i = i + 1
|
i = i + 1
|
||||||
local node_id = t[option]
|
local node_id = t[option]
|
||||||
@ -191,11 +196,17 @@ do
|
|||||||
remarks = "HAProxy负载均衡节点列表[" .. i .. "]",
|
remarks = "HAProxy负载均衡节点列表[" .. i .. "]",
|
||||||
currentNode = node_id and uci:get_all(appname, node_id) or nil,
|
currentNode = node_id and uci:get_all(appname, node_id) or nil,
|
||||||
set = function(o, server)
|
set = function(o, server)
|
||||||
uci:set(appname, t[".name"], option, server)
|
-- 如果当前 lbss 值不是 ip:port 格式,才进行修改
|
||||||
o.newNodeId = server
|
if not is_ip_port(t[option]) then
|
||||||
|
uci:set(appname, t[".name"], option, server)
|
||||||
|
o.newNodeId = server
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
delete = function(o)
|
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
|
||||||
}
|
}
|
||||||
end)
|
end)
|
||||||
@ -1294,19 +1305,21 @@ local function processData(szType, content, add_mode, add_from)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function curl(url, file, ua, mode)
|
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
|
if ua and ua ~= "" and ua ~= "curl" then
|
||||||
table.insert(curl_args, '--user-agent "' .. ua .. '"')
|
curl_args[#curl_args + 1] = '--user-agent "' .. ua .. '"'
|
||||||
end
|
end
|
||||||
local return_code
|
local return_code, result
|
||||||
if mode == "direct" then
|
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
|
elseif mode == "proxy" then
|
||||||
return_code = api.curl_proxy(url, file, curl_args)
|
return_code, result = api.curl_proxy(url, file, curl_args)
|
||||||
else
|
else
|
||||||
return_code = api.curl_auto(url, file, curl_args)
|
return_code, result = api.curl_auto(url, file, curl_args)
|
||||||
end
|
end
|
||||||
return return_code
|
return tonumber(result)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function truncate_nodes(add_from)
|
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)
|
log('成功解析【' .. add_from .. '】节点数量: ' .. #node_list)
|
||||||
else
|
else
|
||||||
if add_mode == "2" then
|
if add_mode == "2" then
|
||||||
log('获取到的【' .. add_from .. '】订阅内容为空,可能是订阅地址失效,或是网络问题,请请检测。')
|
log('获取到的【' .. add_from .. '】订阅内容为空,可能是订阅地址无效,或是网络问题,请诊断!')
|
||||||
end
|
end
|
||||||
end
|
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 "自动"))
|
local result = (not access_mode) and "自动" or (access_mode == "direct" and "直连访问" or (access_mode == "proxy" and "通过代理" or "自动"))
|
||||||
log('正在订阅:【' .. remark .. '】' .. url .. ' [' .. result .. ']')
|
log('正在订阅:【' .. remark .. '】' .. url .. ' [' .. result .. ']')
|
||||||
local tmp_file = "/tmp/" .. cfgid
|
local tmp_file = "/tmp/" .. cfgid
|
||||||
local raw = curl(url, tmp_file, ua, access_mode)
|
value.http_code = curl(url, tmp_file, ua, access_mode)
|
||||||
if raw == 0 then
|
if value.http_code ~= 200 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
|
|
||||||
fail_list[#fail_list + 1] = value
|
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
|
end
|
||||||
allowInsecure_default = true
|
allowInsecure_default = true
|
||||||
filter_keyword_mode_default = uci:get(appname, "@global_subscribe[0]", "filter_keyword_mode") or "0"
|
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
|
if #fail_list > 0 then
|
||||||
for index, value in ipairs(fail_list) do
|
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
|
||||||
end
|
end
|
||||||
update_node(0)
|
update_node(0)
|
||||||
|
Loading…
Reference in New Issue
Block a user