* Changed Makefiles to use mainline Lua
[project/luci.git] / core / src / dispatcher.lua
1 --[[
2 FFLuCI - 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("ffluci.dispatcher", package.seeall)
27 require("ffluci.http")
28 require("ffluci.sys")
29 require("ffluci.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 ffluci.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         ffluci.http.status(404, "Not Found")
49         message = message or "Not Found"
50         
51         require("ffluci.template")
52         if not pcall(ffluci.template.render, "error404") then
53                 ffluci.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         ffluci.http.status(500, "Internal Server Error")
62         
63         require("ffluci.template")
64         if not pcall(ffluci.template.render, "error500", {message=message}) then
65                 ffluci.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 = ffluci.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("ffluci.i18n").loadc(track.i18n)
101         end
102         
103         if track.setuser then
104                 ffluci.sys.process.setuser(track.setuser)
105         end
106         
107         if track.setgroup then
108                 ffluci.sys.process.setgroup(track.setgroup)
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 = ffluci.sys.libpath() .. "/controller/"
128         local suff = ".lua"
129         for i,c in ipairs(ffluci.fs.glob(root .. "*/*" .. suff)) do
130                 c = "ffluci.controller." .. c:sub(#root+1, #c-#suff):gsub("/", ".", 1)
131                 stat, mod = pcall(require, c)
132         
133                 if stat and mod and type(mod.index) == "function" then
134                         ffluci.util.updfenv(mod.index, ffluci.dispatcher)
135                         pcall(mod.index)
136                 end
137         end
138 end
139
140 -- Shortcut for creating a dispatching node
141 function entry(path, target, title, order, add)
142         add = add or {}
143
144         local c = node(path)
145         c.target = target
146         c.title  = title
147         c.order  = order
148         
149         for k,v in pairs(add) do
150                 c[k] = v
151         end
152         
153         return c
154 end
155
156 -- Fetch a dispatching node
157 function node(...)
158         local c = tree
159         
160         if arg[1] and type(arg[1]) == "table" then
161                 arg = arg[1]
162         end
163         
164         for k,v in ipairs(arg) do
165                 if not c.nodes[v] then
166                         c.nodes[v] = {nodes={}}
167                 end
168                 
169                 c = c.nodes[v]
170         end
171         
172         return c
173 end
174
175 -- Subdispatchers --
176 function alias(...)
177         local req = arg
178         return function()
179                 request = req
180                 dispatch()
181         end
182 end
183
184 function template(name)
185         require("ffluci.template")
186         return function() ffluci.template.render(name) end
187 end
188
189 function cbi(model)
190         require("ffluci.cbi")
191         require("ffluci.template")
192         
193         return function()
194                 local stat, res = pcall(ffluci.cbi.load, model)
195                 if not stat then
196                         error500(res)
197                         return true
198                 end
199                 
200                 local stat, err = pcall(res.parse, res)
201                 if not stat then
202                         error500(err)
203                         return true
204                 end
205                 
206                 ffluci.template.render("cbi/header")
207                 res:render()
208                 ffluci.template.render("cbi/footer")
209         end
210 end