mirror of
				https://github.com/kenzok8/openwrt-packages.git
				synced 2025-10-30 07:50:37 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			339 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			339 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| local fs = require "nixio.fs"
 | |
| local sys = require "luci.sys"
 | |
| local uci = require"luci.model.uci".cursor()
 | |
| local util = require "luci.util"
 | |
| local i18n = require "luci.i18n"
 | |
| 
 | |
| module("luci.model.cbi.filebrowser.api", package.seeall)
 | |
| 
 | |
| local appname = "filebrowser"
 | |
| local api_url =
 | |
|     "https://api.github.com/repos/filebrowser/filebrowser/releases/latest"
 | |
| 
 | |
| local wget = "/usr/bin/wget"
 | |
| local wget_args = {
 | |
|     "--no-check-certificate", "--quiet", "--timeout=10", "--tries=2"
 | |
| }
 | |
| local command_timeout = 300
 | |
| 
 | |
| local LEDE_BOARD = nil
 | |
| local DISTRIB_TARGET = nil
 | |
| 
 | |
| function uci_get_type(type, config, default)
 | |
|     value = uci:get_first(appname, type, config, default) or sys.exec(
 | |
|                 "echo -n `uci -q get " .. appname .. ".@" .. type .. "[0]." ..
 | |
|                     config .. "`")
 | |
|     if (value == nil or value == "") and (default and default ~= "") then
 | |
|         value = default
 | |
|     end
 | |
|     return value
 | |
| end
 | |
| 
 | |
| local function _unpack(t, i)
 | |
|     i = i or 1
 | |
|     if t[i] ~= nil then return t[i], _unpack(t, i + 1) end
 | |
| end
 | |
| 
 | |
| local function exec(cmd, args, writer, timeout)
 | |
|     local os = require "os"
 | |
|     local nixio = require "nixio"
 | |
| 
 | |
|     local fdi, fdo = nixio.pipe()
 | |
|     local pid = nixio.fork()
 | |
| 
 | |
|     if pid > 0 then
 | |
|         fdo:close()
 | |
| 
 | |
|         if writer or timeout then
 | |
|             local starttime = os.time()
 | |
|             while true do
 | |
|                 if timeout and os.difftime(os.time(), starttime) >= timeout then
 | |
|                     nixio.kill(pid, nixio.const.SIGTERM)
 | |
|                     return 1
 | |
|                 end
 | |
| 
 | |
|                 if writer then
 | |
|                     local buffer = fdi:read(2048)
 | |
|                     if buffer and #buffer > 0 then
 | |
|                         writer(buffer)
 | |
|                     end
 | |
|                 end
 | |
| 
 | |
|                 local wpid, stat, code = nixio.waitpid(pid, "nohang")
 | |
| 
 | |
|                 if wpid and stat == "exited" then return code end
 | |
| 
 | |
|                 if not writer and timeout then nixio.nanosleep(1) end
 | |
|             end
 | |
|         else
 | |
|             local wpid, stat, code = nixio.waitpid(pid)
 | |
|             return wpid and stat == "exited" and code
 | |
|         end
 | |
|     elseif pid == 0 then
 | |
|         nixio.dup(fdo, nixio.stdout)
 | |
|         fdi:close()
 | |
|         fdo:close()
 | |
|         nixio.exece(cmd, args, nil)
 | |
|         nixio.stdout:close()
 | |
|         os.exit(1)
 | |
|     end
 | |
| end
 | |
| 
 | |
| local function compare_versions(ver1, comp, ver2)
 | |
|     local table = table
 | |
| 
 | |
|     local av1 = util.split(ver1, "[%.%-]", nil, true)
 | |
|     local av2 = util.split(ver2, "[%.%-]", nil, true)
 | |
| 
 | |
|     local max = table.getn(av1)
 | |
|     local n2 = table.getn(av2)
 | |
|     if (max < n2) then max = n2 end
 | |
| 
 | |
|     for i = 1, max, 1 do
 | |
|         local s1 = av1[i] or ""
 | |
|         local s2 = av2[i] or ""
 | |
| 
 | |
|         if comp == "~=" and (s1 ~= s2) then return true end
 | |
|         if (comp == "<" or comp == "<=") and (s1 < s2) then return true end
 | |
|         if (comp == ">" or comp == ">=") and (s1 > s2) then return true end
 | |
|         if (s1 ~= s2) then return false end
 | |
|     end
 | |
| 
 | |
|     return not (comp == "<" or comp == ">")
 | |
| end
 | |
| 
 | |
| local function auto_get_arch()
 | |
|     local arch = nixio.uname().machine or ""
 | |
|     if fs.access("/usr/lib/os-release") then
 | |
|         LEDE_BOARD = sys.exec(
 | |
|                          "echo -n `grep 'LEDE_BOARD' /usr/lib/os-release | awk -F '[\\042\\047]' '{print $2}'`")
 | |
|     end
 | |
|     if fs.access("/etc/openwrt_release") then
 | |
|         DISTRIB_TARGET = sys.exec(
 | |
|                              "echo -n `grep 'DISTRIB_TARGET' /etc/openwrt_release | awk -F '[\\042\\047]' '{print $2}'`")
 | |
|     end
 | |
| 
 | |
|     if arch == "mips" then
 | |
|         if LEDE_BOARD and LEDE_BOARD ~= "" then
 | |
|             if string.match(LEDE_BOARD, "ramips") == "ramips" then
 | |
|                 arch = "ramips"
 | |
|             else
 | |
|                 arch = sys.exec("echo '" .. LEDE_BOARD ..
 | |
|                                     "' | grep -oE 'ramips|ar71xx'")
 | |
|             end
 | |
|         elseif DISTRIB_TARGET and DISTRIB_TARGET ~= "" then
 | |
|             if string.match(DISTRIB_TARGET, "ramips") == "ramips" then
 | |
|                 arch = "ramips"
 | |
|             else
 | |
|                 arch = sys.exec("echo '" .. DISTRIB_TARGET ..
 | |
|                                     "' | grep -oE 'ramips|ar71xx'")
 | |
|             end
 | |
|         end
 | |
|     end
 | |
| 
 | |
|     return util.trim(arch)
 | |
| end
 | |
| 
 | |
| local function get_file_info(arch)
 | |
|     local file_tree = ""
 | |
|     local sub_version = ""
 | |
| 
 | |
|     if arch == "x86_64" then
 | |
|         file_tree = "amd64"
 | |
|     elseif arch == "aarch64" then
 | |
|         file_tree = "arm64"
 | |
|     elseif arch == "ramips" then
 | |
|         file_tree = "mipsle"
 | |
|     elseif arch == "ar71xx" then
 | |
|         file_tree = "mips"
 | |
|     elseif arch:match("^i[%d]86$") then
 | |
|         file_tree = "386"
 | |
|     elseif arch:match("^armv[5-8]") then
 | |
|         file_tree = "armv"
 | |
|         sub_version = arch:match("[5-8]")
 | |
|         if LEDE_BOARD and string.match(LEDE_BOARD, "bcm53xx") == "bcm53xx" then
 | |
|             sub_version = "5"
 | |
|         elseif DISTRIB_TARGET and string.match(DISTRIB_TARGET, "bcm53xx") ==
 | |
|             "bcm53xx" then
 | |
|             sub_version = "5"
 | |
|         end
 | |
|         sub_version = "5"
 | |
|     end
 | |
| 
 | |
|     return file_tree, sub_version
 | |
| end
 | |
| 
 | |
| local function get_api_json(url)
 | |
|     local jsonc = require "luci.jsonc"
 | |
| 
 | |
|     local output = {}
 | |
|     -- exec(wget, { "-O-", url, _unpack(wget_args) },
 | |
|     --	function(chunk) output[#output + 1] = chunk end)
 | |
|     -- local json_content = util.trim(table.concat(output))
 | |
| 
 | |
|     local json_content = luci.sys.exec(wget ..
 | |
|                                            " --no-check-certificate --timeout=10 -t 1 -O- " ..
 | |
|                                            url)
 | |
| 
 | |
|     if json_content == "" then return {} end
 | |
| 
 | |
|     return jsonc.parse(json_content) or {}
 | |
| end
 | |
| 
 | |
| function get_version() return uci_get_type("global", "version", "0") end
 | |
| 
 | |
| function to_check(arch)
 | |
|     if not arch or arch == "" then arch = auto_get_arch() end
 | |
| 
 | |
|     local file_tree, sub_version = get_file_info(arch)
 | |
| 
 | |
|     if file_tree == "" then
 | |
|         return {
 | |
|             code = 1,
 | |
|             error = i18n.translate(
 | |
|                 "Can't determine ARCH, or ARCH not supported.")
 | |
|         }
 | |
|     end
 | |
| 
 | |
|     local json = get_api_json(api_url)
 | |
| 
 | |
|     if json.tag_name == nil then
 | |
|         return {
 | |
|             code = 1,
 | |
|             error = i18n.translate("Get remote version info failed.")
 | |
|         }
 | |
|     end
 | |
| 
 | |
|     local remote_version = json.tag_name:match("[^v]+")
 | |
| 
 | |
|     local needs_update = compare_versions(get_version(), "<", remote_version)
 | |
|     local html_url, download_url
 | |
| 
 | |
|     if needs_update then
 | |
|         html_url = json.html_url
 | |
|         for _, v in ipairs(json.assets) do
 | |
|             if v.name and v.name:match("linux%-" .. file_tree .. sub_version) then
 | |
|                 download_url = v.browser_download_url
 | |
|                 break
 | |
|             end
 | |
|         end
 | |
|     end
 | |
| 
 | |
|     if needs_update and not download_url then
 | |
|         return {
 | |
|             code = 1,
 | |
|             version = remote_version,
 | |
|             html_url = html_url,
 | |
|             error = i18n.translate(
 | |
|                 "New version found, but failed to get new version download url.")
 | |
|         }
 | |
|     end
 | |
| 
 | |
|     return {
 | |
|         code = 0,
 | |
|         update = needs_update,
 | |
|         version = remote_version,
 | |
|         url = {html = html_url, download = download_url}
 | |
|     }
 | |
| end
 | |
| 
 | |
| function to_download(url)
 | |
|     if not url or url == "" then
 | |
|         return {code = 1, error = i18n.translate("Download url is required.")}
 | |
|     end
 | |
| 
 | |
|     sys.call("/bin/rm -f /tmp/filebrowser_download.*")
 | |
| 
 | |
|     local tmp_file = util.trim(util.exec(
 | |
|                                    "mktemp -u -t filebrowser_download.XXXXXX"))
 | |
| 
 | |
|     local result = exec(wget, {"-O", tmp_file, url, _unpack(wget_args)}, nil,
 | |
|                         command_timeout) == 0
 | |
| 
 | |
|     if not result then
 | |
|         exec("/bin/rm", {"-f", tmp_file})
 | |
|         return {
 | |
|             code = 1,
 | |
|             error = i18n.translatef("File download failed or timed out: %s", url)
 | |
|         }
 | |
|     end
 | |
| 
 | |
|     return {code = 0, file = tmp_file}
 | |
| end
 | |
| 
 | |
| function to_extract(file, subfix)
 | |
|     if not file or file == "" or not fs.access(file) then
 | |
|         return {code = 1, error = i18n.translate("File path required.")}
 | |
|     end
 | |
| 
 | |
|     sys.call("/bin/rm -rf /tmp/filebrowser_extract.*")
 | |
|     local tmp_dir = util.trim(util.exec(
 | |
|                                   "mktemp -d -t filebrowser_extract.XXXXXX"))
 | |
| 
 | |
|     local output = {}
 | |
|     exec("/bin/tar", {"-C", tmp_dir, "-zxvf", file},
 | |
|          function(chunk) output[#output + 1] = chunk end)
 | |
| 
 | |
|     local files = util.split(table.concat(output))
 | |
| 
 | |
|     exec("/bin/rm", {"-f", file})
 | |
| 
 | |
|     if not new_file then
 | |
|         for _, f in pairs(files) do
 | |
|             if f:match("filebrowser") then
 | |
|                 new_file = tmp_dir .. "/" .. util.trim(f)
 | |
|                 break
 | |
|             end
 | |
|         end
 | |
|     end
 | |
| 
 | |
|     if not new_file then
 | |
|         exec("/bin/rm", {"-rf", tmp_dir})
 | |
|         return {
 | |
|             code = 1,
 | |
|             error = i18n.translatef("Can't find client in file: %s", file)
 | |
|         }
 | |
|     end
 | |
| 
 | |
|     return {code = 0, file = new_file}
 | |
| end
 | |
| 
 | |
| function to_move(file)
 | |
|     if not file or file == "" or not fs.access(file) then
 | |
|         sys.call("/bin/rm -rf /tmp/filebrowser_extract.*")
 | |
|         return {code = 1, error = i18n.translate("Client file is required.")}
 | |
|     end
 | |
|     local executable_directory =
 | |
|         uci_get_type("global", "executable_directory", "/tmp")
 | |
|     luci.sys.exec("mkdir -p " .. executable_directory)
 | |
|     local client_path = executable_directory .. "/" .. appname
 | |
|     local client_path_bak
 | |
| 
 | |
|     if fs.access(client_path) then
 | |
|         client_path_bak = "/tmp/" .. appname .. ".bak"
 | |
|         exec("/bin/mv", {"-f", client_path, client_path_bak})
 | |
|     end
 | |
| 
 | |
|     local result = exec("/bin/mv", {"-f", file, client_path}, nil,
 | |
|                         command_timeout) == 0
 | |
| 
 | |
|     if not result or not fs.access(client_path) then
 | |
|         if client_path_bak then
 | |
|             exec("/bin/mv", {"-f", client_path_bak, client_path})
 | |
|         end
 | |
|         return {
 | |
|             code = 1,
 | |
|             error = i18n.translatef("Can't move new file to path: %s",
 | |
|                                     client_path)
 | |
|         }
 | |
|     end
 | |
| 
 | |
|     exec("/bin/chmod", {"755", client_path})
 | |
| 
 | |
|     if client_path_bak then exec("/bin/rm", {"-f", client_path_bak}) end
 | |
| 
 | |
|     sys.call("/bin/rm -rf /tmp/filebrowser_extract.*")
 | |
| 
 | |
|     return {code = 0}
 | |
| end
 | 
