84c665edab6b173f4e6589d9e5cf24dda2ad46e7
[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
141 -- Fetch a dispatching node
142 function node(...)
143 local c = tree
144
145 for k,v in ipairs(arg) do
146 if not c.nodes[v] then
147 c.nodes[v] = {nodes={}}
148 end
149
150 c = c.nodes[v]
151 end
152
153 return c
154 end
155
156 -- Subdispatchers --
157 function alias(...)
158 local req = arg
159 return function()
160 request = req
161 dispatch()
162 end
163 end
164
165 function template(name)
166 require("ffluci.template")
167 return function() ffluci.template.render(name) end
168 end
169
170 function cbi(model)
171 require("ffluci.cbi")
172 require("ffluci.template")
173
174 return function()
175 local stat, res = pcall(ffluci.cbi.load, model)
176 if not stat then
177 error500(res)
178 return true
179 end
180
181 local stat, err = pcall(res.parse, res)
182 if not stat then
183 error500(err)
184 return true
185 end
186
187 ffluci.template.render("cbi/header")
188 res:render()
189 ffluci.template.render("cbi/footer")
190 end
191 end