Renamed FFLuCI to LuCI, ffluci to luci and Freifunk Lua Configuration Interface to...
[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