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)
31 -- Local dispatch database
32 local tree = {nodes={}}
37 -- Global request object
40 -- Active dispatched node
49 function build_url(...)
50 return luci.http.dispatcher() .. "/" .. table.concat(arg, "/")
53 -- Sends a 404 error code and renders the "error404" template if available
54 function error404(message)
55 luci.http.status(404, "Not Found")
56 message = message or "Not Found"
58 require("luci.template")
59 if not pcall(luci.template.render, "error404") then
60 luci.http.prepare_content("text/plain")
66 -- Sends a 500 error code and renders the "error500" template if available
67 function error500(message)
68 luci.http.status(500, "Internal Server Error")
70 require("luci.template")
71 if not pcall(luci.template.render, "error500", {message=message}) then
72 luci.http.prepare_content("text/plain")
78 -- Creates a request object for dispatching
79 function httpdispatch()
80 local pathinfo = luci.http.env.PATH_INFO or ""
83 for s in pathinfo:gmatch("([%w-]+)") do
84 table.insert(request, s)
90 -- Dispatches a request
92 if not built_tree then
99 for i, s in ipairs(request) do
101 if not c or c.leaf then
105 for k, v in pairs(c) do
112 require("luci.i18n").loadc(track.i18n)
115 if track.setgroup then
116 luci.sys.process.setgroup(track.setgroup)
119 if track.setuser then
120 luci.sys.process.setuser(track.setuser)
123 -- Init template engine
124 local tpl = require("luci.template")
125 tpl.viewns.translate = function(...) return require("luci.i18n").translate(...) end
126 tpl.viewns.controller = luci.http.dispatcher()
127 tpl.viewns.uploadctrl = luci.http.dispatcher_upload()
128 tpl.viewns.media = luci.config.main.mediaurlbase
129 tpl.viewns.resource = luci.config.main.resourcebase
130 tpl.viewns.REQUEST_URI = luci.http.env.SCRIPT_NAME .. luci.http.env.PATH_INFO
133 if c and type(c.target) == "function" then
135 stat, mod = pcall(require, c.module)
137 luci.util.updfenv(c.target, mod)
140 stat, err = pcall(c.target)
149 -- Generates the dispatching tree
150 function createindex()
152 local path = luci.sys.libpath() .. "/controller/"
155 --[[if pcall(require, "fastindex") then
156 createindex_fastindex(path, suff)
158 createindex_plain(path, suff)
161 createindex_plain(path, suff)
166 -- Uses fastindex to create the dispatching tree
167 function createindex_fastindex(path, suffix)
168 local fi = fastindex.new("index")
169 fi.add(path .. "*" .. suffix)
170 fi.add(path .. "*/*" .. suffix)
173 for k, v in pairs(fi.indexes) do
178 -- Calls the index function of all available controllers
179 function createindex_plain(path, suffix)
182 local controllers = luci.util.combine(
183 luci.fs.glob(path .. "*" .. suffix) or {},
184 luci.fs.glob(path .. "*/*" .. suffix) or {}
188 cache = luci.fs.mtime(indexcache)
191 luci.fs.mkdir(indexcache)
192 luci.fs.chmod(indexcache, "a=,u=rwx")
193 cache = luci.fs.mtime(indexcache)
197 for i,c in ipairs(controllers) do
198 local module = "luci.controller." .. c:sub(#path+1, #c-#suffix):gsub("/", ".")
199 local cachefile = indexcache .. "/" .. module
204 stime = luci.fs.mtime(c) or 0
205 ctime = luci.fs.mtime(cachefile) or 0
208 if not cache or stime > ctime then
209 stat, mod = pcall(require, module)
211 if stat and mod and type(mod.index) == "function" then
212 index[module] = mod.index
215 luci.fs.writefile(cachefile, luci.util.dump(mod.index))
219 index[module] = loadfile(cachefile)
224 -- Creates the dispatching tree from the index
225 function createtree()
226 if not built_index then
232 -- Load default translation
233 luci.i18n.loadc("default")
235 local scope = luci.util.clone(_G)
236 for k,v in pairs(_M) do
237 if type(v) == "function" then
242 for k, v in pairs(index) do
246 local stat, err = pcall(v)
256 -- Shortcut for creating a dispatching node
257 function entry(path, target, title, order, add)
264 c.module = getfenv(2)._NAME
266 for k,v in pairs(add) do
273 -- Fetch a dispatching node
277 if arg[1] and type(arg[1]) == "table" then
281 for k,v in ipairs(arg) do
282 if not c.nodes[v] then
283 c.nodes[v] = {nodes={}, module=getfenv(2)._NAME}
301 function rewrite(n, ...)
305 table.remove(request, 1)
308 for i,r in ipairs(req) do
309 table.insert(request, i, r)
317 return function() getfenv()[name]() end
320 function template(name)
321 require("luci.template")
322 return function() luci.template.render(name) end
327 require("luci.template")
330 local stat, res = pcall(luci.cbi.load, model)
336 local stat, err = pcall(res.parse, res)
342 luci.template.render("cbi/header")
344 luci.template.render("cbi/footer")