daf975e9defa6d6506987bb3ef280e243c3af6b6
[project/luci.git] / core / src / dispatcher.lua
1 --[[
2 LuCI - Dispatcher
3
4 Description:
5 The request dispatcher and module dispatcher generators
6
7 FileId:
8 $Id$
9
10 License:
11 Copyright 2008 Steven Barth <steven@midlink.org>
12
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
16
17         http://www.apache.org/licenses/LICENSE-2.0
18
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.
24
25 ]]--
26 module("luci.dispatcher", package.seeall)
27 require("luci.http")
28 require("luci.sys")
29 require("luci.fs")
30
31 -- Local dispatch database
32 local tree = {nodes={}}
33
34 -- Global request object
35 request = {}
36
37 -- Active dispatched node
38 dispatched = nil
39
40
41 -- Builds a URL
42 function build_url(...)
43         return luci.http.dispatcher() .. "/" .. table.concat(arg, "/")
44 end
45
46 -- Sends a 404 error code and renders the "error404" template if available
47 function error404(message)
48         luci.http.status(404, "Not Found")
49         message = message or "Not Found"
50
51         require("luci.template")
52         if not pcall(luci.template.render, "error404") then
53                 luci.http.prepare_content("text/plain")
54                 print(message)
55         end
56         return false
57 end
58
59 -- Sends a 500 error code and renders the "error500" template if available
60 function error500(message)
61         luci.http.status(500, "Internal Server Error")
62
63         require("luci.template")
64         if not pcall(luci.template.render, "error500", {message=message}) then
65                 luci.http.prepare_content("text/plain")
66                 print(message)
67         end
68         return false
69 end
70
71 -- Dispatches a request depending on the PATH_INFO variable
72 function httpdispatch()
73         local pathinfo = luci.http.env.PATH_INFO or ""
74         local c = tree
75
76         for s in pathinfo:gmatch("/([%w-]+)") do
77                 table.insert(request, s)
78         end
79
80         dispatch()
81 end
82
83 function dispatch()
84         local c = tree
85         local track = {}
86
87         for i, s in ipairs(request) do
88                 c = c.nodes[s]
89                 if not c then
90                         break
91                 end
92
93                 for k, v in pairs(c) do
94                         track[k] = v
95                 end
96         end
97
98
99         if track.i18n then
100                 require("luci.i18n").loadc(track.i18n)
101         end
102
103         if track.setgroup then
104                 luci.sys.process.setgroup(track.setgroup)
105         end
106
107         if track.setuser then
108                 luci.sys.process.setuser(track.setuser)
109         end
110
111
112         if c and type(c.target) == "function" then
113                 dispatched = c
114
115                 stat, err = pcall(c.target)
116                 if not stat then
117                         error500(err)
118                 end
119         else
120                 error404()
121         end
122 end
123
124
125 -- Calls the index function of all available controllers
126 function createindex()
127         local root = luci.sys.libpath() .. "/controller/"
128         local suff = ".lua"
129
130         local controllers = luci.util.combine(
131                 luci.fs.glob(root .. "*" .. suff),
132                 luci.fs.glob(root .. "*/*" .. suff)
133         )
134
135         for i,c in ipairs(controllers) do
136                 c = "luci.controller." .. c:sub(#root+1, #c-#suff):gsub("/", ".")
137                 stat, mod = pcall(require, c)
138
139                 if stat and mod and type(mod.index) == "function" then
140                         luci.util.updfenv(mod.index, luci.dispatcher)
141                         pcall(mod.index)
142                 end
143         end
144 end
145
146 -- Shortcut for creating a dispatching node
147 function entry(path, target, title, order, add)
148         add = add or {}
149
150         local c = node(path)
151         c.target = target
152         c.title  = title
153         c.order  = order
154
155         for k,v in pairs(add) do
156                 c[k] = v
157         end
158
159         return c
160 end
161
162 -- Fetch a dispatching node
163 function node(...)
164         local c = tree
165
166         if arg[1] and type(arg[1]) == "table" then
167                 arg = arg[1]
168         end
169
170         for k,v in ipairs(arg) do
171                 if not c.nodes[v] then
172                         c.nodes[v] = {nodes={}}
173                 end
174
175                 c = c.nodes[v]
176         end
177
178         return c
179 end
180
181 -- Subdispatchers --
182 function alias(...)
183         local req = arg
184         return function()
185                 request = req
186                 dispatch()
187         end
188 end
189
190 function template(name)
191         require("luci.template")
192         return function() luci.template.render(name) end
193 end
194
195 function cbi(model)
196         require("luci.cbi")
197         require("luci.template")
198
199         return function()
200                 local stat, res = pcall(luci.cbi.load, model)
201                 if not stat then
202                         error500(res)
203                         return true
204                 end
205
206                 local stat, err = pcall(res.parse, res)
207                 if not stat then
208                         error500(err)
209                         return true
210                 end
211
212                 luci.template.render("cbi/header")
213                 res:render()
214                 luci.template.render("cbi/footer")
215         end
216 end