mirror of
https://github.com/coolsnowwolf/lede.git
synced 2025-06-18 15:25:29 +08:00
luci-app-ssr-plus: optimize subscribe script and support ssd subscribe (#2726)
* luci-app-ssr-plus: optimize subscribe script and support ssd subscribe * luci-app-ssr-plus: optimize ping test and added socket test * luci-app-ssr-plus: fix script path * luci-app-ssr-plus: optimize script * luci-app-ssr-plus: optimize script and remove /tmp/ssrpro.log * luci-app-ssr-plus: adjust log function * luci-app-ssr-plus: fix index * luci-app-ssr-plus: adjust content
This commit is contained in:
parent
4da966dae3
commit
9fcb30d870
@ -9,26 +9,28 @@ function index()
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
entry({"admin", "services", "shadowsocksr"},alias("admin", "services", "shadowsocksr", "client"),_("ShadowSocksR Plus+"), 10).dependent = true
|
entry({"admin", "services", "shadowsocksr"}, alias("admin", "services", "shadowsocksr", "client"),_("ShadowSocksR Plus+"), 10).dependent = true
|
||||||
|
|
||||||
entry({"admin", "services", "shadowsocksr", "client"},cbi("shadowsocksr/client"),_("SSR Client"), 10).leaf = true
|
entry({"admin", "services", "shadowsocksr", "client"}, cbi("shadowsocksr/client"),_("SSR Client"), 10).leaf = true
|
||||||
|
|
||||||
entry({"admin", "services", "shadowsocksr", "servers"}, arcombine(cbi("shadowsocksr/servers", {autoapply=true}), cbi("shadowsocksr/client-config")),_("Severs Nodes"), 20).leaf = true
|
entry({"admin", "services", "shadowsocksr", "servers"}, arcombine(cbi("shadowsocksr/servers", {autoapply=true}), cbi("shadowsocksr/client-config")),_("Severs Nodes"), 20).leaf = true
|
||||||
|
|
||||||
entry({"admin", "services", "shadowsocksr", "control"},cbi("shadowsocksr/control"),_("Access Control"), 30).leaf = true
|
entry({"admin", "services", "shadowsocksr", "control"},cbi("shadowsocksr/control"), _("Access Control"), 30).leaf = true
|
||||||
|
|
||||||
-- entry({"admin", "services", "shadowsocksr", "list"},form("shadowsocksr/list"),_("GFW List"), 40).leaf = true
|
-- entry({"admin", "services", "shadowsocksr", "list"},form("shadowsocksr/list"),_("GFW List"), 40).leaf = true
|
||||||
|
|
||||||
entry({"admin", "services", "shadowsocksr", "advanced"},cbi("shadowsocksr/advanced"),_("Advanced Settings"), 50).leaf = true
|
entry({"admin", "services", "shadowsocksr", "advanced"},cbi("shadowsocksr/advanced"),_("Advanced Settings"), 50).leaf = true
|
||||||
|
|
||||||
if nixio.fs.access("/usr/bin/ssr-server") then
|
if nixio.fs.access("/usr/bin/ssr-server") then
|
||||||
entry({"admin", "services", "shadowsocksr", "server"},arcombine(cbi("shadowsocksr/server"), cbi("shadowsocksr/server-config")),_("SSR Server"), 60).leaf = true
|
entry({"admin", "services", "shadowsocksr", "server"},arcombine(cbi("shadowsocksr/server"), cbi("shadowsocksr/server-config")),_("SSR Server"), 60).leaf = true
|
||||||
end
|
end
|
||||||
|
|
||||||
entry({"admin", "services", "shadowsocksr", "status"},form("shadowsocksr/status"),_("Status"), 70).leaf = true
|
entry({"admin", "services", "shadowsocksr", "status"},form("shadowsocksr/status"),_("Status"), 70).leaf = true
|
||||||
|
|
||||||
entry({"admin", "services", "shadowsocksr", "check"}, call("check_status"))
|
entry({"admin", "services", "shadowsocksr", "check"}, call("check_status"))
|
||||||
entry({"admin", "services", "shadowsocksr", "refresh"}, call("refresh_data"))
|
entry({"admin", "services", "shadowsocksr", "refresh"}, call("refresh_data"))
|
||||||
|
entry({"admin", "services", "shadowsocksr", "subscribe"}, call("subscribe"))
|
||||||
|
|
||||||
entry({"admin", "services", "shadowsocksr", "checkport"}, call("check_port"))
|
entry({"admin", "services", "shadowsocksr", "checkport"}, call("check_port"))
|
||||||
|
|
||||||
entry({"admin", "services", "shadowsocksr", "log"},form("shadowsocksr/log"),_("Log"), 80).leaf = true
|
entry({"admin", "services", "shadowsocksr", "log"},form("shadowsocksr/log"),_("Log"), 80).leaf = true
|
||||||
@ -39,31 +41,49 @@ function index()
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function subscribe()
|
||||||
|
luci.sys.call("/usr/bin/lua /usr/share/shadowsocksr/subscribe.lua >> /tmp/ssrplus.log 2>&1")
|
||||||
|
luci.http.prepare_content("application/json")
|
||||||
|
luci.http.write_json({ ret = 1 })
|
||||||
|
end
|
||||||
|
|
||||||
function act_status()
|
function act_status()
|
||||||
local e={}
|
local e={}
|
||||||
e.running=luci.sys.call("busybox ps -w | grep ssr-retcp | grep -v grep >/dev/null")==0
|
e.running=luci.sys.call("busybox ps -w | grep ssr-retcp | grep -v grep >/dev/null")==0
|
||||||
luci.http.prepare_content("application/json")
|
luci.http.prepare_content("application/json")
|
||||||
luci.http.write_json(e)
|
luci.http.write_json(e)
|
||||||
end
|
end
|
||||||
|
|
||||||
function act_ping()
|
function act_ping()
|
||||||
local e={}
|
local e = {}
|
||||||
e.index=luci.http.formvalue("index")
|
local domain = luci.http.formvalue("domain")
|
||||||
e.ping=luci.sys.exec("ping -c 1 -W 1 %q 2>&1 | grep -o 'time=[0-9]*.[0-9]' | awk -F '=' '{print$2}'"%luci.http.formvalue("domain"))
|
local port = luci.http.formvalue("port")
|
||||||
luci.http.prepare_content("application/json")
|
e.index = luci.http.formvalue("index")
|
||||||
luci.http.write_json(e)
|
e.ping = luci.sys.exec("ping -c 1 -W 1 %q 2>&1 | grep -o 'time=[0-9]*.[0-9]' | awk -F '=' '{print$2}'" % domain)
|
||||||
|
|
||||||
|
local iret = luci.sys.call(" ipset add ss_spec_wan_ac " .. domain .. " 2>/dev/null")
|
||||||
|
local socket = nixio.socket("inet", "stream")
|
||||||
|
socket:setopt("socket", "rcvtimeo", 3)
|
||||||
|
socket:setopt("socket", "sndtimeo", 3)
|
||||||
|
e.socket = socket:connect(domain, port)
|
||||||
|
socket:close()
|
||||||
|
if (iret == 0) then
|
||||||
|
luci.sys.call(" ipset del ss_spec_wan_ac " .. domain)
|
||||||
|
end
|
||||||
|
luci.http.prepare_content("application/json")
|
||||||
|
luci.http.write_json(e)
|
||||||
end
|
end
|
||||||
|
|
||||||
function check_status()
|
function check_status()
|
||||||
local set ="/usr/bin/ssr-check www." .. luci.http.formvalue("set") .. ".com 80 3 1"
|
local set = "/usr/bin/ssr-check www." .. luci.http.formvalue("set") .. ".com 80 3 1"
|
||||||
sret=luci.sys.call(set)
|
sret = luci.sys.call(set)
|
||||||
if sret== 0 then
|
if sret == 0 then
|
||||||
retstring ="0"
|
retstring ="0"
|
||||||
else
|
else
|
||||||
retstring ="1"
|
retstring ="1"
|
||||||
end
|
end
|
||||||
luci.http.prepare_content("application/json")
|
luci.http.prepare_content("application/json")
|
||||||
luci.http.write_json({ ret=retstring })
|
luci.http.write_json({ ret=retstring })
|
||||||
end
|
end
|
||||||
|
|
||||||
function refresh_data()
|
function refresh_data()
|
||||||
@ -72,82 +92,82 @@ local icount =0
|
|||||||
|
|
||||||
if set == "gfw_data" then
|
if set == "gfw_data" then
|
||||||
if nixio.fs.access("/usr/bin/wget-ssl") then
|
if nixio.fs.access("/usr/bin/wget-ssl") then
|
||||||
refresh_cmd="wget-ssl --no-check-certificate https://cdn.jsdelivr.net/gh/gfwlist/gfwlist/gfwlist.txt -O /tmp/gfw.b64"
|
refresh_cmd="wget-ssl --no-check-certificate https://cdn.jsdelivr.net/gh/gfwlist/gfwlist/gfwlist.txt -O /tmp/gfw.b64"
|
||||||
else
|
else
|
||||||
refresh_cmd="wget -O /tmp/gfw.b64 http://iytc.net/tools/list.b64"
|
refresh_cmd="wget -O /tmp/gfw.b64 http://iytc.net/tools/list.b64"
|
||||||
end
|
end
|
||||||
sret=luci.sys.call(refresh_cmd .. " 2>/dev/null")
|
sret=luci.sys.call(refresh_cmd .. " 2>/dev/null")
|
||||||
if sret== 0 then
|
if sret== 0 then
|
||||||
luci.sys.call("/usr/bin/ssr-gfw")
|
luci.sys.call("/usr/bin/ssr-gfw")
|
||||||
icount = luci.sys.exec("cat /tmp/gfwnew.txt | wc -l")
|
icount = luci.sys.exec("cat /tmp/gfwnew.txt | wc -l")
|
||||||
if tonumber(icount)>1000 then
|
if tonumber(icount)>1000 then
|
||||||
oldcount=luci.sys.exec("cat /etc/dnsmasq.ssr/gfw_list.conf | wc -l")
|
oldcount=luci.sys.exec("cat /etc/dnsmasq.ssr/gfw_list.conf | wc -l")
|
||||||
if tonumber(icount) ~= tonumber(oldcount) then
|
if tonumber(icount) ~= tonumber(oldcount) then
|
||||||
luci.sys.exec("cp -f /tmp/gfwnew.txt /etc/dnsmasq.ssr/gfw_list.conf")
|
luci.sys.exec("cp -f /tmp/gfwnew.txt /etc/dnsmasq.ssr/gfw_list.conf")
|
||||||
retstring=tostring(math.ceil(tonumber(icount)/2))
|
retstring=tostring(math.ceil(tonumber(icount)/2))
|
||||||
else
|
else
|
||||||
retstring ="0"
|
retstring ="0"
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
retstring ="-1"
|
retstring ="-1"
|
||||||
end
|
end
|
||||||
luci.sys.exec("rm -f /tmp/gfwnew.txt ")
|
luci.sys.exec("rm -f /tmp/gfwnew.txt ")
|
||||||
else
|
else
|
||||||
retstring ="-1"
|
retstring ="-1"
|
||||||
end
|
end
|
||||||
elseif set == "ip_data" then
|
elseif set == "ip_data" then
|
||||||
refresh_cmd="wget -O- 'http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest' 2>/dev/null| awk -F\\| '/CN\\|ipv4/ { printf(\"%s/%d\\n\", $4, 32-log($5)/log(2)) }' > /tmp/china_ssr.txt"
|
refresh_cmd="wget -O- 'http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest' 2>/dev/null| awk -F\\| '/CN\\|ipv4/ { printf(\"%s/%d\\n\", $4, 32-log($5)/log(2)) }' > /tmp/china_ssr.txt"
|
||||||
sret=luci.sys.call(refresh_cmd)
|
sret=luci.sys.call(refresh_cmd)
|
||||||
icount = luci.sys.exec("cat /tmp/china_ssr.txt | wc -l")
|
icount = luci.sys.exec("cat /tmp/china_ssr.txt | wc -l")
|
||||||
if sret== 0 and tonumber(icount)>1000 then
|
if sret== 0 and tonumber(icount)>1000 then
|
||||||
oldcount=luci.sys.exec("cat /etc/china_ssr.txt | wc -l")
|
oldcount=luci.sys.exec("cat /etc/china_ssr.txt | wc -l")
|
||||||
if tonumber(icount) ~= tonumber(oldcount) then
|
if tonumber(icount) ~= tonumber(oldcount) then
|
||||||
luci.sys.exec("cp -f /tmp/china_ssr.txt /etc/china_ssr.txt")
|
luci.sys.exec("cp -f /tmp/china_ssr.txt /etc/china_ssr.txt")
|
||||||
retstring=tostring(tonumber(icount))
|
retstring=tostring(tonumber(icount))
|
||||||
else
|
else
|
||||||
retstring ="0"
|
retstring ="0"
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
retstring ="-1"
|
retstring ="-1"
|
||||||
end
|
end
|
||||||
luci.sys.exec("rm -f /tmp/china_ssr.txt ")
|
luci.sys.exec("rm -f /tmp/china_ssr.txt ")
|
||||||
else
|
else
|
||||||
local need_process = 0
|
local need_process = 0
|
||||||
if nixio.fs.access("/usr/bin/wget-ssl") then
|
if nixio.fs.access("/usr/bin/wget-ssl") then
|
||||||
refresh_cmd="wget-ssl --no-check-certificate -O - https://easylist-downloads.adblockplus.org/easylistchina+easylist.txt > /tmp/adnew.conf"
|
refresh_cmd="wget-ssl --no-check-certificate -O - https://easylist-downloads.adblockplus.org/easylistchina+easylist.txt > /tmp/adnew.conf"
|
||||||
need_process = 1
|
need_process = 1
|
||||||
else
|
else
|
||||||
refresh_cmd="wget -O /tmp/ad.conf http://iytc.net/tools/ad.conf"
|
refresh_cmd="wget -O /tmp/ad.conf http://iytc.net/tools/ad.conf"
|
||||||
end
|
end
|
||||||
sret=luci.sys.call(refresh_cmd .. " 2>/dev/null")
|
sret=luci.sys.call(refresh_cmd .. " 2>/dev/null")
|
||||||
if sret== 0 then
|
if sret== 0 then
|
||||||
if need_process == 1 then
|
if need_process == 1 then
|
||||||
luci.sys.call("/usr/bin/ssr-ad")
|
luci.sys.call("/usr/bin/ssr-ad")
|
||||||
end
|
end
|
||||||
icount = luci.sys.exec("cat /tmp/ad.conf | wc -l")
|
icount = luci.sys.exec("cat /tmp/ad.conf | wc -l")
|
||||||
if tonumber(icount)>1000 then
|
if tonumber(icount)>1000 then
|
||||||
if nixio.fs.access("/etc/dnsmasq.ssr/ad.conf") then
|
if nixio.fs.access("/etc/dnsmasq.ssr/ad.conf") then
|
||||||
oldcount=luci.sys.exec("cat /etc/dnsmasq.ssr/ad.conf | wc -l")
|
oldcount=luci.sys.exec("cat /etc/dnsmasq.ssr/ad.conf | wc -l")
|
||||||
else
|
else
|
||||||
oldcount=0
|
oldcount=0
|
||||||
end
|
end
|
||||||
|
|
||||||
if tonumber(icount) ~= tonumber(oldcount) then
|
if tonumber(icount) ~= tonumber(oldcount) then
|
||||||
luci.sys.exec("cp -f /tmp/ad.conf /etc/dnsmasq.ssr/ad.conf")
|
luci.sys.exec("cp -f /tmp/ad.conf /etc/dnsmasq.ssr/ad.conf")
|
||||||
retstring=tostring(math.ceil(tonumber(icount)))
|
retstring=tostring(math.ceil(tonumber(icount)))
|
||||||
if oldcount==0 then
|
if oldcount==0 then
|
||||||
luci.sys.call("/etc/init.d/dnsmasq restart")
|
luci.sys.call("/etc/init.d/dnsmasq restart")
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
retstring ="0"
|
retstring ="0"
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
retstring ="-1"
|
retstring ="-1"
|
||||||
end
|
end
|
||||||
luci.sys.exec("rm -f /tmp/ad.conf ")
|
luci.sys.exec("rm -f /tmp/ad.conf ")
|
||||||
else
|
else
|
||||||
retstring ="-1"
|
retstring ="-1"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
luci.http.prepare_content("application/json")
|
luci.http.prepare_content("application/json")
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
local fs = require "nixio.fs"
|
|
||||||
local conffile = "/tmp/ssrpro.log"
|
|
||||||
|
|
||||||
f = SimpleForm("logview")
|
f = SimpleForm("logview")
|
||||||
f.reset = false
|
f.reset = false
|
||||||
f.submit = false
|
f.submit = false
|
||||||
@ -8,8 +5,12 @@ t = f:field(TextValue, "conf")
|
|||||||
t.rmempty = true
|
t.rmempty = true
|
||||||
t.rows = 20
|
t.rows = 20
|
||||||
function t.cfgvalue()
|
function t.cfgvalue()
|
||||||
luci.sys.exec("[ -f /tmp/ssrplus.log ] && sed '1!G;h;$!d' /tmp/ssrplus.log > /tmp/ssrpro.log")
|
local logs = luci.util.execi("cat /tmp/ssrplus.log")
|
||||||
return fs.readfile(conffile) or ""
|
local s = ""
|
||||||
|
for line in logs do
|
||||||
|
s = line .. "\n" .. s
|
||||||
|
end
|
||||||
|
return s
|
||||||
end
|
end
|
||||||
t.readonly="readonly"
|
t.readonly="readonly"
|
||||||
|
|
||||||
|
@ -45,12 +45,18 @@ o = s:option(Flag, "proxy", translate("Through proxy update"))
|
|||||||
o.rmempty = false
|
o.rmempty = false
|
||||||
o.description = translate("Through proxy update list, Not Recommended ")
|
o.description = translate("Through proxy update list, Not Recommended ")
|
||||||
|
|
||||||
o = s:option(Button,"update",translate("Update All Subscribe Severs"))
|
o = s:option(Button,"subscribe", translate("Update All Subscribe Severs"))
|
||||||
o.inputstyle = "apply"
|
o.rawhtml = true
|
||||||
o.write = function()
|
o.template = "shadowsocksr/subscribe"
|
||||||
luci.sys.exec("bash /usr/share/shadowsocksr/subscribe.sh >>/tmp/ssrplus.log 2>&1")
|
|
||||||
luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers"))
|
|
||||||
end
|
-- o.inputstyle = "apply"
|
||||||
|
-- o.write = function()
|
||||||
|
-- luci.sys.call("lua /root/subscribe.lua >>/tmp/ssrplus.log 2>&1")
|
||||||
|
-- -- luci.sys.call("echo 123 >>/tmp/ssrplus.log 2>&1")
|
||||||
|
-- --luci.sys.exec("bash /usr/share/shadowsocksr/subscribe.sh >>/tmp/ssrplus.log 2>&1")
|
||||||
|
-- luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers"))
|
||||||
|
-- end
|
||||||
|
|
||||||
|
|
||||||
o = s:option(Button,"delete",translate("Delete all severs"))
|
o = s:option(Button,"delete",translate("Delete all severs"))
|
||||||
@ -113,7 +119,11 @@ function o.cfgvalue(...)
|
|||||||
return Value.cfgvalue(...) or "0"
|
return Value.cfgvalue(...) or "0"
|
||||||
end
|
end
|
||||||
|
|
||||||
o = s:option(DummyValue,"server",translate("Ping Latency"))
|
o = s:option(DummyValue, "server_port", translate("Socket Connected"))
|
||||||
|
o.template="shadowsocksr/socket"
|
||||||
|
o.width="10%"
|
||||||
|
|
||||||
|
o = s:option(DummyValue, "server", translate("Ping Latency"))
|
||||||
o.template="shadowsocksr/ping"
|
o.template="shadowsocksr/ping"
|
||||||
o.width="10%"
|
o.width="10%"
|
||||||
|
|
||||||
|
@ -9,16 +9,56 @@ local dsp = require "luci.dispatcher"
|
|||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
//<![CDATA[
|
//<![CDATA[
|
||||||
var pings = document.getElementsByClassName('pingtime');
|
const doms = document.getElementsByClassName('pingtime');
|
||||||
for(var i = 0; i < pings.length; i++) {
|
const ports = document.getElementsByClassName("socket-connected")
|
||||||
XHR.get('<%=dsp.build_url("admin/services/shadowsocksr/ping")%>', {
|
// 这也是卡的原罪 CGI 一下子处理不这么多
|
||||||
index: i,
|
const xhr = (index) => {
|
||||||
domain: pings[i].getAttribute("hint")
|
return new Promise((res) => {
|
||||||
|
const dom = doms[index];
|
||||||
|
const port = ports[index];
|
||||||
|
if (!dom) res()
|
||||||
|
XHR.get('<%=dsp.build_url("admin/services/shadowsocksr/ping")%>', {
|
||||||
|
index,
|
||||||
|
domain: dom.getAttribute("hint"),
|
||||||
|
port: port.getAttribute("hint")
|
||||||
},
|
},
|
||||||
function(x, result) {
|
(x, result) => {
|
||||||
pings[result.index].innerHTML = (result.ping ? result.ping : "--") + " ms";
|
let col = '#ff0000';
|
||||||
}
|
if (result.ping) {
|
||||||
);
|
if (result.ping < 300) col = '#ff3300';
|
||||||
|
if (result.ping < 200) col = '#ff7700';
|
||||||
|
if (result.ping < 100) col = '#249400';
|
||||||
|
}
|
||||||
|
dom.innerHTML = `<font color="${col}">${(result.ping ? result.ping : "--") + " ms"}</font>`
|
||||||
|
if (result.socket) {
|
||||||
|
port.innerHTML = '<font color="#249400">ok</font>'
|
||||||
|
} else {
|
||||||
|
port.innerHTML = '<font color="#ff0000">fail</font>'
|
||||||
|
}
|
||||||
|
res()
|
||||||
|
});
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
(async () => {
|
||||||
|
for (let group = 0; group < Math.ceil(doms.length / 5); group++) {
|
||||||
|
await Promise.all([
|
||||||
|
xhr(group * 5 + 0),
|
||||||
|
xhr(group * 5 + 1),
|
||||||
|
xhr(group * 5 + 2),
|
||||||
|
xhr(group * 5 + 3),
|
||||||
|
xhr(group * 5 + 4),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
// for(var i = 0; i < pings.length; i++) {
|
||||||
|
// XHR.get('<%=dsp.build_url("admin/services/shadowsocksr/ping")%>', {
|
||||||
|
// index: i,
|
||||||
|
// domain: pings[i].getAttribute("hint")
|
||||||
|
// },
|
||||||
|
// function(x, result) {
|
||||||
|
// pings[result.index].innerHTML = (result.ping ? result.ping : "--") + " ms";
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
// }
|
||||||
//]]>
|
//]]>
|
||||||
</script>
|
</script>
|
@ -0,0 +1,3 @@
|
|||||||
|
<%+cbi/valueheader%>
|
||||||
|
<span class="socket-connected" hint="<%=self:cfgvalue(section)%>">connecting</:wqspan>
|
||||||
|
<%+cbi/valuefooter%>
|
@ -0,0 +1,23 @@
|
|||||||
|
<%+cbi/valueheader%>
|
||||||
|
|
||||||
|
<script type="text/javascript">//<![CDATA[
|
||||||
|
|
||||||
|
function subscribe(btn,dataname) {
|
||||||
|
btn.disabled = true;
|
||||||
|
btn.value = '<%:Refresh...%> ';
|
||||||
|
murl=dataname;
|
||||||
|
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "shadowsocksr","subscribe")%>', { set:murl }, function(x,rv) {
|
||||||
|
// 先简单刷新,后期如果重构会考虑下如何组织lua shell JavaScript之间的代码逻辑和各自的调用逻辑
|
||||||
|
window.location.reload()
|
||||||
|
// btn.disabled = false;
|
||||||
|
// btn.value = '<%:Refresh Data %>';
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//]]></script>
|
||||||
|
|
||||||
|
|
||||||
|
<input type="button" class="cbi-button cbi-input-apply" value="<%:Update All Subscribe Severs%> " onclick="return subscribe(this,'<%=self.option%>')" />
|
||||||
|
<!-- <span id="<%=self.option%>-status"><em><%=self.value%></em></span> -->
|
||||||
|
|
||||||
|
<%+cbi/valuefooter%>
|
@ -512,6 +512,9 @@ msgstr "所有端口(默认)"
|
|||||||
msgid "Only Common Ports"
|
msgid "Only Common Ports"
|
||||||
msgstr "仅常用端口(不走P2P流量到代理)"
|
msgstr "仅常用端口(不走P2P流量到代理)"
|
||||||
|
|
||||||
|
msgid "Socket Connected"
|
||||||
|
msgstr "连接测试"
|
||||||
|
|
||||||
msgid "Ping Latency"
|
msgid "Ping Latency"
|
||||||
msgstr "Ping延迟"
|
msgstr "Ping延迟"
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ add_cron()
|
|||||||
{
|
{
|
||||||
sed -i '/shadowsocksr/d' $CRON_FILE
|
sed -i '/shadowsocksr/d' $CRON_FILE
|
||||||
sed -i '/ssrplus.log/d' $CRON_FILE && echo '0 1 * * * echo "" > /tmp/ssrplus.log' >> $CRON_FILE
|
sed -i '/ssrplus.log/d' $CRON_FILE && echo '0 1 * * * echo "" > /tmp/ssrplus.log' >> $CRON_FILE
|
||||||
[ $(uci_get_by_type server_subscribe auto_update 0) -eq 1 ] && echo "0 $(uci_get_by_type server_subscribe auto_update_time) * * * /usr/share/shadowsocksr/subscribe.sh" >> $CRON_FILE
|
[ $(uci_get_by_type server_subscribe auto_update 0) -eq 1 ] && echo "0 $(uci_get_by_type server_subscribe auto_update_time) * * * /usr/bin/lua /usr/share/shadowsocksr/subscribe.lua" >> $CRON_FILE
|
||||||
[ $(uci_get_by_type server_subscribe auto_update 0) -eq 1 ] && echo "0 $(uci_get_by_type server_subscribe auto_update_time) * * * /usr/share/shadowsocksr/update.sh" >> $CRON_FILE
|
[ $(uci_get_by_type server_subscribe auto_update 0) -eq 1 ] && echo "0 $(uci_get_by_type server_subscribe auto_update_time) * * * /usr/share/shadowsocksr/update.sh" >> $CRON_FILE
|
||||||
crontab $CRON_FILE
|
crontab $CRON_FILE
|
||||||
}
|
}
|
||||||
|
295
package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua
Executable file
295
package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua
Executable file
@ -0,0 +1,295 @@
|
|||||||
|
#!/usr/bin/lua
|
||||||
|
------------------------------------------------
|
||||||
|
-- This file is part of the luci-app-ssr-plus subscribe.lua
|
||||||
|
-- @author William Chan <root@williamchan.me>
|
||||||
|
------------------------------------------------
|
||||||
|
require 'nixio'
|
||||||
|
require 'luci.util'
|
||||||
|
require 'luci.jsonc'
|
||||||
|
require 'luci.sys'
|
||||||
|
|
||||||
|
-- these global functions are accessed all the time by the event handler
|
||||||
|
-- so caching them is worth the effort
|
||||||
|
local tinsert = table.insert
|
||||||
|
local ssub, slen, schar, srep, sbyte, sformat, sgsub =
|
||||||
|
string.sub, string.len, string.char, string.rep, string.byte, string.format, string.gsub
|
||||||
|
local cache = {}
|
||||||
|
local nodeResult = setmetatable({}, { __index = cache }) -- update result
|
||||||
|
local name = 'shadowsocksr'
|
||||||
|
local uciType = 'servers'
|
||||||
|
local ucic = luci.model.uci.cursor()
|
||||||
|
local proxy = ucic:get_first(name, 'server_subscribe', 'proxy', '0')
|
||||||
|
local subscribe_url = ucic:get_first(name, 'server_subscribe', 'subscribe_url', {})
|
||||||
|
|
||||||
|
local log = function(...)
|
||||||
|
print(os.date("%Y-%m-%d %H:%M:%S ") .. table.concat({ ... }, " "))
|
||||||
|
end
|
||||||
|
-- 分割字符串
|
||||||
|
local function split(full, sep)
|
||||||
|
full = full:gsub("%z", "") -- 这里不是很清楚 有时候结尾带个\0
|
||||||
|
local off, result = 1, {}
|
||||||
|
while true do
|
||||||
|
local nEnd = full:find(sep, off)
|
||||||
|
if not nEnd then
|
||||||
|
local res = ssub(full, off, slen(full))
|
||||||
|
if #res > 0 then -- 过滤掉 \0
|
||||||
|
tinsert(result, res)
|
||||||
|
end
|
||||||
|
break
|
||||||
|
else
|
||||||
|
tinsert(result, ssub(full, off, nEnd - 1))
|
||||||
|
off = nEnd + slen(sep)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
-- urlencode
|
||||||
|
local function get_urlencode(c)
|
||||||
|
return sformat("%%%02X", sbyte(c))
|
||||||
|
end
|
||||||
|
|
||||||
|
function urlEncode(szText)
|
||||||
|
local str = szText:gsub("([^0-9a-zA-Z ])", get_urlencode)
|
||||||
|
str = str:gsub(" ", "+")
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
-- trim
|
||||||
|
local function trim(text)
|
||||||
|
if not text or text == "" then
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
return (sgsub(text, "^%s*(.-)%s*$", "%1"))
|
||||||
|
end
|
||||||
|
-- md5
|
||||||
|
local function md5(content)
|
||||||
|
local stdout = luci.sys.exec('echo \"' .. urlEncode(content) .. '\" | md5sum | cut -d \" \" -f1')
|
||||||
|
-- assert(nixio.errno() == 0)
|
||||||
|
return trim(stdout)
|
||||||
|
end
|
||||||
|
-- base64
|
||||||
|
local function base64Decode(text, safe)
|
||||||
|
if not text then return '' end
|
||||||
|
text = text:gsub("%z", "")
|
||||||
|
if safe then
|
||||||
|
text = text:gsub("_", "/")
|
||||||
|
text = text:gsub("-", "+")
|
||||||
|
local mod4 = #text % 4
|
||||||
|
text = text .. string.sub('====', mod4 + 1)
|
||||||
|
end
|
||||||
|
return nixio.bin.b64decode(text):gsub("%z", "")
|
||||||
|
end
|
||||||
|
-- 处理数据
|
||||||
|
local function processData(szType, content)
|
||||||
|
local result = {
|
||||||
|
auth_enable = '0',
|
||||||
|
switch_enable = '1',
|
||||||
|
type = szType,
|
||||||
|
local_port = 1234,
|
||||||
|
timeout = 60, -- 不太确定 好像是死的
|
||||||
|
fast_open = 0,
|
||||||
|
kcp_enable = 0,
|
||||||
|
kcp_port = 0,
|
||||||
|
kcp_param = '--nocomp'
|
||||||
|
}
|
||||||
|
local hash
|
||||||
|
if type(content) == 'string' then
|
||||||
|
hash = md5(content)
|
||||||
|
else
|
||||||
|
hash = md5(luci.jsonc.stringify(content))
|
||||||
|
end
|
||||||
|
result.hashkey = hash
|
||||||
|
if szType == 'ssr' then
|
||||||
|
local dat = split(content, "/\\?")
|
||||||
|
local hostInfo = split(dat[1], ':')
|
||||||
|
result.server = hostInfo[1]
|
||||||
|
result.server_port = hostInfo[2]
|
||||||
|
result.protocol = hostInfo[3]
|
||||||
|
result.encrypt_method = hostInfo[4]
|
||||||
|
result.obfs = hostInfo[5]
|
||||||
|
result.password = base64Decode(hostInfo[6], true)
|
||||||
|
local params = {}
|
||||||
|
for k, v in pairs(split(dat[2], '&')) do
|
||||||
|
local t = split(v, '=')
|
||||||
|
params[t[1]] = t[2]
|
||||||
|
end
|
||||||
|
result.obfs_param = base64Decode(params.bfsparam, true)
|
||||||
|
result.protocol_param = base64Decode(params.protoparam, true)
|
||||||
|
local group = base64Decode(params.group, true)
|
||||||
|
if group then
|
||||||
|
result.alias = "[" .. group .. "] "
|
||||||
|
end
|
||||||
|
result.alias = result.alias .. base64Decode(params.remarks, true)
|
||||||
|
elseif szType == 'vmess' then
|
||||||
|
local info = luci.jsonc.parse(content)
|
||||||
|
result.type = 'v2ray'
|
||||||
|
result.server = info.add
|
||||||
|
result.server_port = info.port
|
||||||
|
result.tcp_guise = "none"
|
||||||
|
result.transport = info.net
|
||||||
|
result.alter_id = info.aid
|
||||||
|
result.vmess_id = info.id
|
||||||
|
result.alias = info.ps
|
||||||
|
result.ws_host = info.host
|
||||||
|
result.ws_path = info.path
|
||||||
|
result.h2_host = info.host
|
||||||
|
result.h2_path = info.path
|
||||||
|
if not info.security then
|
||||||
|
result.security = 'auto'
|
||||||
|
end
|
||||||
|
if info.tls == 'tls' or info.tls == '1' then
|
||||||
|
result.tls = '1'
|
||||||
|
else
|
||||||
|
result.tls = '0'
|
||||||
|
end
|
||||||
|
elseif szType == 'ssd' then
|
||||||
|
result.type = 'ss'
|
||||||
|
result.server = content.server
|
||||||
|
result.server_port = content.port
|
||||||
|
result.password = content.password
|
||||||
|
result.encrypt_method_ss = content.encryption
|
||||||
|
result.alias = '[' .. content.airport .. '] ' .. content.remarks
|
||||||
|
end
|
||||||
|
return result, hash
|
||||||
|
end
|
||||||
|
-- wget
|
||||||
|
local function wget(url)
|
||||||
|
local stdout = luci.sys.exec('wget-ssl --user-agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36" --no-check-certificate -t 3 -T 10 -O- ' .. url)
|
||||||
|
return trim(stdout)
|
||||||
|
end
|
||||||
|
|
||||||
|
local execute = function()
|
||||||
|
-- exec
|
||||||
|
do
|
||||||
|
-- subscribe_url = {'https://www.google.comc'}
|
||||||
|
if proxy == '0' then -- 不使用代理更新的话先暂停
|
||||||
|
log('服务正在暂停')
|
||||||
|
luci.sys.init.stop(name)
|
||||||
|
end
|
||||||
|
for k, url in ipairs(subscribe_url) do
|
||||||
|
local raw = wget(url)
|
||||||
|
if #raw > 0 then
|
||||||
|
local node, szType
|
||||||
|
local groupHash = md5(url)
|
||||||
|
cache[groupHash] = {}
|
||||||
|
tinsert(nodeResult, {})
|
||||||
|
local index = #nodeResult
|
||||||
|
-- SSD 似乎是这种格式 ssd:// 开头的 不知道 SS 什么格式 没支持 不清楚其他机场是否这样
|
||||||
|
if raw:find('ssd://') then
|
||||||
|
szType = 'ssd'
|
||||||
|
local nEnd = select(2, raw:find('ssd://'))
|
||||||
|
node = base64Decode(raw:sub(nEnd + 1, #raw), true)
|
||||||
|
node = luci.jsonc.parse(node)
|
||||||
|
local extra = {
|
||||||
|
airport = node.airport,
|
||||||
|
port = node.port,
|
||||||
|
encryption = node.encryption,
|
||||||
|
password = node.password
|
||||||
|
}
|
||||||
|
local servers = {}
|
||||||
|
-- SS里面包着 干脆直接这样
|
||||||
|
for _, server in ipairs(node.servers) do
|
||||||
|
tinsert(servers, setmetatable(server, { __index = extra }))
|
||||||
|
end
|
||||||
|
node = servers
|
||||||
|
else
|
||||||
|
-- ssd 外的格式
|
||||||
|
node = split(base64Decode(raw, true), "\n")
|
||||||
|
end
|
||||||
|
for _, v in ipairs(node) do
|
||||||
|
if v then
|
||||||
|
local result, hash
|
||||||
|
if szType == 'ssd' then
|
||||||
|
result, hash = processData(szType, v)
|
||||||
|
elseif not szType then
|
||||||
|
local dat = split(v, "://")
|
||||||
|
if dat and dat[1] and dat[2] then
|
||||||
|
result, hash = processData(dat[1], base64Decode( dat[2], true))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log('跳过未知类型: ' .. szType)
|
||||||
|
end
|
||||||
|
-- log(hash, result)
|
||||||
|
if hash and result then
|
||||||
|
if result.alias:find("过期时间") or
|
||||||
|
result.alias:find("剩余流量") or
|
||||||
|
result.alias:find("QQ群") or
|
||||||
|
result.alias:find("官网") or
|
||||||
|
result.server == ''
|
||||||
|
then
|
||||||
|
log('丢弃无效节点: ' .. result.type ..' 节点, ' .. result.alias)
|
||||||
|
else
|
||||||
|
log('成功解析: ' .. result.type ..' 节点, ' .. result.alias)
|
||||||
|
result.grouphashkey = groupHash
|
||||||
|
tinsert(nodeResult[index], result)
|
||||||
|
cache[groupHash][hash] = nodeResult[index][#nodeResult[index]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
log('成功解析节点数量: ' ..#node)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- diff
|
||||||
|
do
|
||||||
|
assert(next(nodeResult))
|
||||||
|
local add, del = 0, 0
|
||||||
|
ucic:foreach(name, uciType, function(old)
|
||||||
|
if old.grouphashkey or old.hashkey then -- 没有 hash 的不参与删除
|
||||||
|
if not nodeResult[old.grouphashkey] or not nodeResult[old.grouphashkey][old.hashkey] then
|
||||||
|
ucic:delete(name, old['.name'])
|
||||||
|
del = del + 1
|
||||||
|
else
|
||||||
|
local dat = nodeResult[old.grouphashkey][old.hashkey]
|
||||||
|
ucic:tset(name, old['.name'], dat)
|
||||||
|
-- 标记一下
|
||||||
|
setmetatable(nodeResult[old.grouphashkey][old.hashkey], { __index = { _ignore = true } })
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log('忽略手动添加的节点: ' .. old.alias)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
for k, v in ipairs(nodeResult) do
|
||||||
|
for kk, vv in ipairs(v) do
|
||||||
|
if not vv._ignore then
|
||||||
|
local section = ucic:add(name, uciType)
|
||||||
|
ucic:tset(name, section, vv)
|
||||||
|
add = add + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
ucic:commit(name)
|
||||||
|
-- 如果服务器已经不见了把帮换一个
|
||||||
|
local globalServer = ucic:get_first(name, 'global', 'global_server', '')
|
||||||
|
local firstServer = ucic:get_first(name, uciType)
|
||||||
|
if not ucic:get(name, globalServer) then
|
||||||
|
if firstServer then
|
||||||
|
ucic:set(name, ucic:get_first(name, 'global'), 'global_server', firstServer)
|
||||||
|
ucic:commit(name)
|
||||||
|
log('当前主服务器已更新,正在自动更换。')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if firstServer then
|
||||||
|
luci.sys.call("/etc/init.d/" .. name .." restart > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早
|
||||||
|
else
|
||||||
|
luci.sys.call("/etc/init.d/" .. name .." stop > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早
|
||||||
|
end
|
||||||
|
log('新增节点数量: ' ..add, '删除节点数量: ' .. del)
|
||||||
|
log('更新成功服务正在启动')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if subscribe_url and #subscribe_url > 0 then
|
||||||
|
xpcall(execute, function()
|
||||||
|
log('发生错误, 正在恢复服务')
|
||||||
|
local firstServer = ucic:get_first(name, uciType)
|
||||||
|
if firstServer then
|
||||||
|
luci.sys.call("/etc/init.d/" .. name .." restart > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早
|
||||||
|
else
|
||||||
|
luci.sys.call("/etc/init.d/" .. name .." stop > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早
|
||||||
|
end
|
||||||
|
log('更新失败服务正在恢复')
|
||||||
|
log(debug.traceback())
|
||||||
|
end)
|
||||||
|
end
|
Loading…
x
Reference in New Issue
Block a user