From 66e6e853be60d2cb3d513e2bbb3b98135562de45 Mon Sep 17 00:00:00 2001 From: Mattraks <16359027+Mattraks@users.noreply.github.com> Date: Sun, 12 Apr 2020 12:04:25 +0800 Subject: [PATCH] luci-app-ssr-plus:revert subscribe.lua (#4282) * luci-app-ssr-plus:Code optimization and Fix Bug * luci-app-ssr-plus:Adjust reference data location * luci-app-ssr-plus:revert subscribe.lua --- package/lean/luci-app-ssr-plus/Makefile | 2 +- .../luasrc/model/cbi/shadowsocksr/status.lua | 2 +- .../root/etc/config/shadowsocksr | 1 - .../root/etc/init.d/shadowsocksr | 2 +- .../root/usr/share/shadowsocksr/subscribe.lua | 239 +++++++----------- 5 files changed, 97 insertions(+), 149 deletions(-) diff --git a/package/lean/luci-app-ssr-plus/Makefile b/package/lean/luci-app-ssr-plus/Makefile index edf07317d..19fe30e56 100644 --- a/package/lean/luci-app-ssr-plus/Makefile +++ b/package/lean/luci-app-ssr-plus/Makefile @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-ssr-plus PKG_VERSION:=176 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua index bd6c6d354..d6edefeb1 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua @@ -46,7 +46,7 @@ if nixio.fs.access("/etc/dnsmasq.ssr/ad.conf") then end if nixio.fs.access("/etc/ssr/china_ssr.txt") then - ip_count = tonumber(luci.sys.exec("cat /etc/china_ssr.txt | wc -l")) + ip_count = tonumber(luci.sys.exec("cat /etc/ssr/china_ssr.txt | wc -l")) end if nixio.fs.access("/etc/ssr/netflixip.list") then diff --git a/package/lean/luci-app-ssr-plus/root/etc/config/shadowsocksr b/package/lean/luci-app-ssr-plus/root/etc/config/shadowsocksr index 7658938ae..f8aac0821 100644 --- a/package/lean/luci-app-ssr-plus/root/etc/config/shadowsocksr +++ b/package/lean/luci-app-ssr-plus/root/etc/config/shadowsocksr @@ -20,7 +20,6 @@ config global option netflix_proxy '0' config access_control - option wan_bp_list '/etc/ssr/china_ssr.txt' option lan_ac_mode 'b' option router_proxy '1' list wan_fw_ips '149.154.160.0/20' diff --git a/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr b/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr index ff6082594..0f6332eed 100755 --- a/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr +++ b/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr @@ -644,7 +644,7 @@ start_rules() { -S "$udp_server" \ -L "$udp_local_port" \ -a "$ac_ips" \ - -i "$(uci_get_by_type access_control wan_bp_list)" \ + -i "/etc/ssr/china_ssr.txt" \ -b "$(uci_get_by_type access_control wan_bp_ips)" \ -w "$(uci_get_by_type access_control wan_fw_ips)" \ -B "$(uci_get_by_type access_control lan_bp_ips)" \ diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua index b7cb1bce9..ff0a201bd 100644 --- a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua @@ -3,60 +3,30 @@ -- This file is part of the luci-app-ssr-plus subscribe.lua -- @author William Chan ------------------------------------------------ -require 'nixio' -require 'luci.util' -require 'luci.jsonc' -require 'luci.sys' -require 'uci' +require "luci.model.uci" +require "nixio" +require "luci.util" +require "luci.sys" +require "luci.jsonc" -- 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, sbyte, sformat, sgsub = string.sub, string.len, string.char, string.byte, string.format, string.gsub local jsonParse, jsonStringify = luci.jsonc.parse, luci.jsonc.stringify local b64decode = nixio.bin.b64decode -local nodeResult = {} -- update result -local application = 'shadowsocksr' +local cache = {} +local nodeResult = setmetatable({}, { __index = cache }) -- update result +local name = 'shadowsocksr' local uciType = 'servers' -local ucic2 = uci.cursor() -local proxy = ucic2:get(application, '@server_subscribe[0]', 'proxy') or '0' -local switch = ucic2:get(application, '@server_subscribe[0]', 'switch') or '1' -local subscribe_url = ucic2:get(application, '@server_subscribe[0]', 'subscribe_url') or {} -local filter_words = ucic2:get(application, '@server_subscribe[0]', 'filter_words') or '过期时间/剩余流量' -ucic2:revert(application) +local ucic = luci.model.uci.cursor() +local proxy = ucic:get_first(name, 'server_subscribe', 'proxy', '0') +local switch = ucic:get_first(name, 'server_subscribe', 'switch', '1') +local subscribe_url = ucic:get_first(name, 'server_subscribe', 'subscribe_url', {}) +local filter_words = ucic:get_first(name, 'server_subscribe', 'filter_words', '过期时间/剩余流量') local log = function(...) print(os.date("%Y-%m-%d %H:%M:%S ") .. table.concat({ ... }, " ")) end - --- 获取各项动态配置的当前服务器,可以用 get 和 set, get必须要获取到节点表 -local CONFIG = { - GLOBAL_SERVER = { - remarks = '主节点', - type = "global", option = "global_server", - set = function(server) - ucic2:set(application, '@global[0]', "global_server", server) - end - } -} -do - for k, v in pairs(CONFIG) do - local currentNode - if v.get then - currentNode = v.get() - else - local cfgid = ucic2:get(application, '@' .. v.type .. '[0]', v.option) - if cfgid then - currentNode = ucic2:get_all(application, cfgid) - end - end - if currentNode then - CONFIG[k].currentNode = currentNode - else - CONFIG[k] = nil - end - end -end - -- 分割字符串 local function split(full, sep) full = full:gsub("%z", "") -- 这里不是很清楚 有时候结尾带个\0 @@ -77,15 +47,15 @@ local function split(full, sep) return result end -- urlencode --- local function get_urlencode(c) --- return sformat("%%%02X", sbyte(c)) --- end +local function get_urlencode(c) + return sformat("%%%02X", sbyte(c)) +end --- local function urlEncode(szText) --- local str = szText:gsub("([^0-9a-zA-Z ])", get_urlencode) --- str = str:gsub(" ", "+") --- return str --- end +local function urlEncode(szText) + local str = szText:gsub("([^0-9a-zA-Z ])", get_urlencode) + str = str:gsub(" ", "+") + return str +end local function get_urldecode(h) return schar(tonumber(h, 16)) @@ -101,7 +71,12 @@ local function trim(text) 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) local raw = text @@ -123,8 +98,7 @@ local function processData(szType, content) local result = { type = szType, local_port = 1234, - kcp_param = '--nocomp', - isSubscribe = 1, + kcp_param = '--nocomp' } if szType == 'ssr' then local dat = split(content, "/%?") @@ -288,6 +262,14 @@ local function processData(szType, content) if not result.alias then result.alias = result.server .. ':' .. result.server_port end + -- alias 不参与 hashkey 计算 + local alias = result.alias + result.alias = nil + local switch_enable = result.switch_enable + result.switch_enable = nil + result.hashkey = md5(jsonStringify(result)) + result.alias = alias + result.switch_enable = switch_enable return result end -- wget @@ -308,71 +290,20 @@ local function check_filer(result) end end -local function select_node(nodes, config) - local server - -- 第一优先级 IP + 端口 - for id, node in pairs(nodes) do - if node.server .. ':' .. node.server_port == config.currentNode.server .. ':' .. config.currentNode.server_port then - log('选择【' .. config.remarks .. '】第一匹配节点:' .. node.alias) - server = id - break - end - end - -- 第二优先级 IP - if not server then - for id, node in pairs(nodes) do - if node.server == config.currentNode.server then - log('选择【' .. config.remarks .. '】第二匹配节点:' .. node.alias) - server = id - break - end - end - end - -- 第三优先级备注 - if not server then - for id, node in pairs(nodes) do - if node.alias == config.currentNode.alias then - log('选择【' .. config.remarks .. '】第三匹配节点:' .. node.alias) - server = id - break - end - end - end - -- 第四 cfgid - if not server then - for id, node in pairs(nodes) do - if id == config.currentNode['.name'] then - log('选择【' .. config.remarks .. '】第四匹配节点:' .. node.alias) - server = id - break - end - end - end - -- 还不行 随便找一个 - if not server then - server = ucic2:get(application, '@'.. uciType .. '[0]') - if server then - log('无法找到最匹配的节点,当前已更换为' .. ucic2:get_all(application, server).alias) - end - end - if server then - config.set(server) - end -end - local execute = function() -- exec do if proxy == '0' then -- 不使用代理更新的话先暂停 log('服务正在暂停') - luci.sys.init.stop(application) + luci.sys.init.stop(name) end for k, url in ipairs(subscribe_url) do local raw = wget(url) if #raw > 0 then local nodes, szType - local all_odes = {} - tinsert(nodeResult, all_odes) + local groupHash = md5(url) + cache[groupHash] = {} + tinsert(nodeResult, {}) local index = #nodeResult -- SSD 似乎是这种格式 ssd:// 开头的 if raw:find('ssd://') then @@ -425,7 +356,9 @@ local execute = function() log('丢弃无效节点: ' .. result.type ..' 节点, ' .. result.alias) else log('成功解析: ' .. result.type ..' 节点, ' .. result.alias) - tinsert(all_odes, result) + result.grouphashkey = groupHash + tinsert(nodeResult[index], result) + cache[groupHash][result.hashkey] = nodeResult[index][#nodeResult[index]] end end end @@ -438,45 +371,60 @@ local execute = function() end -- diff do - assert(next(nodeResult), '更新失败,没有可用的节点信息') - -- delete all for subscribe nodes - ucic2:foreach(application, uciType, function(node) - if node.isSubscribe or node.hashkey then -- 兼容之前的hashkey - ucic2:delete(application, node['.name']) + if next(nodeResult) == nil then + log("更新失败,没有可用的节点信息") + return + end + 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 + if not old.alias then + old.alias = old.server .. ':' .. old.server_port + end + log('忽略手动添加的节点: ' .. old.alias) end end) - for _, v in ipairs(nodeResult) do - for _, vv in ipairs(v) do - vv.switch_enable = switch - local cfgid = ucic2:add(application, uciType) - for kkk, vvv in pairs(vv) do - ucic2:set(application, cfgid, kkk, vvv) + 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) + ucic:set(name, section, "switch_enable", switch) + add = add + 1 end end end - ucic2:commit(application) - local ucic3 = uci.cursor() - -- repair configuration - if next(CONFIG) then - local nodes = {} - ucic3:foreach(application, uciType, function(node) - if node.server and node.server_port and node.alias then - nodes[node['.name']] = node - end - end) - for _, config in pairs(CONFIG) do - select_node(nodes, config) + ucic:commit(name) + -- 如果原有服务器节点已经不见了就尝试换为第一个节点 + local globalServer = ucic:get_first(name, 'global', 'global_server', '') + local firstServer = ucic:get_first(name, uciType) + if firstServer then + if not ucic:get(name, globalServer) then + luci.sys.call("/etc/init.d/" .. name .. " stop > /dev/null 2>&1 &") + ucic:commit(name) + ucic:set(name, ucic:get_first(name, 'global'), 'global_server', ucic:get_first(name, uciType)) + ucic:commit(name) + log('当前主服务器节点已被删除,正在自动更换为第一个节点。') + luci.sys.call("/etc/init.d/" .. name .. " start > /dev/null 2>&1 &") + else + log('维持当前主服务器节点。') + luci.sys.call("/etc/init.d/" .. name .." restart > /dev/null 2>&1 &") end - ucic3:commit(application) + else + log('没有服务器节点了,停止服务') + luci.sys.call("/etc/init.d/" .. name .. " stop > /dev/null 2>&1 &") end - -- select first server - local globalServer = ucic3:get(application, '@global[0]', 'global_server') or '' - if not globalServer or not ucic3:get_all(application, globalServer) then - ucic3:set(application, '@global[0]', 'global_server', select(2, ucic3:get(application, '@' .. uciType .. '[0]'))) - ucic3:commit(application) - log('当前没有主节点,自动选择第一个节点开启服务。') - end - luci.sys.call("/etc/init.d/" .. application .." restart > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早 + log('新增节点数量: ' ..add, '删除节点数量: ' .. del) log('订阅更新成功') end end @@ -486,11 +434,12 @@ if subscribe_url and #subscribe_url > 0 then log(e) log(debug.traceback()) log('发生错误, 正在恢复服务') - if CONFIG.GLOBAL_SERVER and CONFIG.GLOBAL_SERVER.currentNode then - luci.sys.call("/etc/init.d/" .. application .." restart > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早 + local firstServer = ucic:get_first(name, uciType) + if firstServer then + luci.sys.call("/etc/init.d/" .. name .." restart > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早 log('重启服务成功') else - luci.sys.call("/etc/init.d/" .. application .." stop > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早 + luci.sys.call("/etc/init.d/" .. name .." stop > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早 log('停止服务成功') end end)