From cf1219bd0790506279b14007595e8389e5eb99ff Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Fri, 6 Dec 2019 21:19:02 +0100 Subject: [PATCH] luci-base: dispatcher.lua: add support for loading JSON menu files Signed-off-by: Jo-Philipp Wich --- modules/luci-base/luasrc/dispatcher.lua | 118 ++++++++++++++++++++++-- 1 file changed, 110 insertions(+), 8 deletions(-) diff --git a/modules/luci-base/luasrc/dispatcher.lua b/modules/luci-base/luasrc/dispatcher.lua index 103215549..d4293422b 100644 --- a/modules/luci-base/luasrc/dispatcher.lua +++ b/modules/luci-base/luasrc/dispatcher.lua @@ -609,14 +609,32 @@ local function find_subnode(root, prefix, recurse, descended) end end +local function merge_trees(node_a, node_b) + for k, v in pairs(node_b) do + if k == "children" then + node_a.children = node_a.children or {} + + for name, spec in pairs(v) do + node_a.children[name] = merge_trees(node_a.children[name] or {}, spec) + end + else + node_a[k] = v + end + end + return node_a +end + function menu_json() local tree = context.tree or createtree() - return tree_to_json(tree, { + local lua_tree = tree_to_json(tree, { action = { ["type"] = "firstchild", ["recurse"] = true } }) + + local json_tree = createtree_json() + return merge_trees(lua_tree, json_tree) end local function init_template_engine(ctx) @@ -961,13 +979,9 @@ function createindex() "' - It must correspond to the file path!") local idx = mod.index - assert(type(idx) == "function", - "Invalid controller file found\n" .. - "The file '" .. path .. "' contains no index() function.\n" .. - "Please make sure that the controller contains a valid " .. - "index function and verify the spelling!") - - index[modname] = idx + if type(idx) == "function" then + index[modname] = idx + end end if indexcache then @@ -977,6 +991,94 @@ function createindex() end end +function createtree_json() + local json = require "luci.jsonc" + local tree = {} + + local schema = { + action = "table", + auth = "table", + cors = "boolean", + depends = "table", + order = "number", + setgroup = "string", + setuser = "string", + title = "string", + wildcard = "boolean" + } + + local files = {} + local fprint = {} + local cachefile + + for file in (fs.glob("/usr/share/luci/menu.d/*.json") or function() end) do + files[#files+1] = file + + if indexcache then + local st = fs.stat(file) + if st then + fprint[#fprint+1] = '%x' % st.ino + fprint[#fprint+1] = '%x' % st.mtime + fprint[#fprint+1] = '%x' % st.size + end + end + end + + if indexcache then + cachefile = "%s.%s.json" %{ + indexcache, + nixio.crypt(table.concat(fprint, "|"), "$1$"):sub(5):gsub("/", ".") + } + + local res = json.parse(fs.readfile(cachefile) or "") + if res then + return res + end + + for file in (fs.glob("%s.*.json" % indexcache) or function() end) do + fs.unlink(file) + end + end + + for _, file in ipairs(files) do + local data = json.parse(fs.readfile(file) or "") + if type(data) == "table" then + for path, spec in pairs(data) do + if type(spec) == "table" then + local node = tree + + for s in path:gmatch("[^/]+") do + if s == "*" then + node.wildcard = true + break + end + + node.children = node.children or {} + node.children[s] = node.children[s] or {} + node = node.children[s] + end + + if node ~= tree then + for k, t in pairs(schema) do + if type(spec[k]) == t then + node[k] = spec[k] + end + end + + node.satisfied = check_depends(spec) + end + end + end + end + end + + if cachefile then + fs.writefile(cachefile, json.stringify(tree)) + end + + return tree +end + -- Build the index before if it does not exist yet. function createtree() if not index then -- 2.25.1