5 The request dispatcher and module dispatcher generators
11 Copyright 2008 Steven Barth <steven@midlink.org>
13 Licensed under the Apache License, Version 2.0 (the "License");
14 you may not use this file except in compliance with the License.
15 You may obtain a copy of the License at
17 http://www.apache.org/licenses/LICENSE-2.0
19 Unless required by applicable law or agreed to in writing, software
20 distributed under the License is distributed on an "AS IS" BASIS,
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 See the License for the specific language governing permissions and
23 limitations under the License.
26 module("luci.dispatcher", package.seeall)
32 if (os.time() < luci.fs.mtime(luci.sys.libpath() .. "/dispatcher.lua")) then
33 os.execute('date -s '..os.date('%m%d%H%M%Y', luci.fs.mtime(luci.sys.libpath() .. "/dispatcher.lua")))
36 -- Local dispatch database
37 local tree = {nodes={}}
42 -- Global request object
45 -- Active dispatched node
54 function build_url(...)
55 return luci.http.dispatcher() .. "/" .. table.concat(arg, "/")
58 -- Sends a 404 error code and renders the "error404" template if available
59 function error404(message)
60 luci.http.status(404, "Not Found")
61 message = message or "Not Found"
63 require("luci.template")
64 if not pcall(luci.template.render, "error404") then
65 luci.http.prepare_content("text/plain")
71 -- Sends a 500 error code and renders the "error500" template if available
72 function error500(message)
73 luci.http.status(500, "Internal Server Error")
75 require("luci.template")
76 if not pcall(luci.template.render, "error500", {message=message}) then
77 luci.http.prepare_content("text/plain")
83 -- Creates a request object for dispatching
84 function httpdispatch()
85 local pathinfo = luci.http.env.PATH_INFO or ""
88 for s in pathinfo:gmatch("([%w-]+)") do
89 table.insert(request, s)
95 -- Dispatches a request
97 if not built_tree then
104 for i, s in ipairs(request) do
106 if not c or c.leaf then
110 for k, v in pairs(c) do
117 require("luci.i18n").loadc(track.i18n)
120 if track.setgroup then
121 luci.sys.process.setgroup(track.setgroup)
124 if track.setuser then
125 luci.sys.process.setuser(track.setuser)
128 -- Init template engine
129 local tpl = require("luci.template")
130 tpl.viewns.translate = function(...) return require("luci.i18n").translate(...) end
131 tpl.viewns.controller = luci.http.dispatcher()
132 tpl.viewns.uploadctrl = luci.http.dispatcher_upload()
133 tpl.viewns.media = luci.config.main.mediaurlbase
134 tpl.viewns.resource = luci.config.main.resourcebase
135 tpl.viewns.REQUEST_URI = luci.http.env.SCRIPT_NAME .. luci.http.env.PATH_INFO
138 if c and type(c.target) == "function" then
140 stat, mod = pcall(require, c.module)
142 luci.util.updfenv(c.target, mod)
145 stat, err = pcall(c.target)
154 -- Generates the dispatching tree
155 function createindex()
157 local path = luci.sys.libpath() .. "/controller/"
160 --[[if pcall(require, "fastindex") then
161 createindex_fastindex(path, suff)
163 createindex_plain(path, suff)
166 createindex_plain(path, suff)
171 -- Uses fastindex to create the dispatching tree
172 function createindex_fastindex(path, suffix)
173 local fi = fastindex.new("index")
174 fi.add(path .. "*" .. suffix)
175 fi.add(path .. "*/*" .. suffix)
178 for k, v in pairs(fi.indexes) do
183 -- Calls the index function of all available controllers
184 function createindex_plain(path, suffix)
187 local controllers = luci.util.combine(
188 luci.fs.glob(path .. "*" .. suffix) or {},
189 luci.fs.glob(path .. "*/*" .. suffix) or {}
193 cache = luci.fs.mtime(indexcache)
196 luci.fs.mkdir(indexcache)
197 luci.fs.chmod(indexcache, "a=,u=rwx")
198 cache = luci.fs.mtime(indexcache)
202 for i,c in ipairs(controllers) do
203 local module = "luci.controller." .. c:sub(#path+1, #c-#suffix):gsub("/", ".")
204 local cachefile = indexcache .. "/" .. module
209 stime = luci.fs.mtime(c) or 0
210 ctime = luci.fs.mtime(cachefile) or 0
213 if not cache or stime > ctime then
214 stat, mod = pcall(require, module)
216 if stat and mod and type(mod.index) == "function" then
217 index[module] = mod.index
220 luci.fs.writefile(cachefile, luci.util.dump(mod.index))
224 index[module] = loadfile(cachefile)
229 -- Creates the dispatching tree from the index
230 function createtree()
231 if not built_index then
237 -- Load default translation
238 luci.i18n.loadc("default")
240 local scope = luci.util.clone(_G)
241 for k,v in pairs(_M) do
242 if type(v) == "function" then
247 for k, v in pairs(index) do
251 local stat, err = pcall(v)
261 -- Shortcut for creating a dispatching node
262 function entry(path, target, title, order, add)
269 c.module = getfenv(2)._NAME
271 for k,v in pairs(add) do
278 -- Fetch a dispatching node
282 if arg[1] and type(arg[1]) == "table" then
286 for k,v in ipairs(arg) do
287 if not c.nodes[v] then
288 c.nodes[v] = {nodes={}, module=getfenv(2)._NAME}
306 function rewrite(n, ...)
310 table.remove(request, 1)
313 for i,r in ipairs(req) do
314 table.insert(request, i, r)
322 return function() getfenv()[name]() end
325 function template(name)
326 require("luci.template")
327 return function() luci.template.render(name) end
332 require("luci.template")
335 local stat, res = pcall(luci.cbi.load, model)
341 local stat, err = pcall(res.parse, res)
347 luci.template.render("cbi/header")
349 luci.template.render("cbi/footer")