This repository has been archived by the owner on Feb 6, 2021. It is now read-only.
/
template.lua
executable file
·228 lines (196 loc) · 5.89 KB
/
template.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
-- Luawa
-- File: template.lua
-- Desc: lhtml templating
local require = require
local tostring = tostring
local pcall = pcall
local loadstring = loadstring
local type = type
local table = table
local io = io
local ngx = ngx
local luawa = require('luawa.core')
local template = {
config = {
dir = ''
},
cache = {},
env = {}
}
-- Init
function template:_init()
self.utils = luawa.utils
self.session = luawa.session
self.request = luawa.request
self.caching = luawa.caching
end
-- Start function
function template:_start()
ngx.ctx.data = {}
--now token is generated, add to template (not API)
self:set('token', self.session:getToken())
end
-- End function
function template:_end()
--if api request output template data as json
if ngx.ctx.api then
local function clean(data)
if type(data) == 'table' then
for k, v in pairs(data) do
data[k] = clean(v)
end
else
if type(data) == 'function' then
data = false
end
end
return data
end
clean(self.data)
self.request:setHeader('Content-Type', 'text/json')
self:set('messages', luawa.session:getMessages(), true)
local out, err = self.utils.json_encode(ngx.ctx.data)
if out then
ngx.ctx.response = out
else
ngx.ctx.response = self.utils.json_encode({ error = err })
end
end
end
-- Set data
function template:set(key, value, api)
--not api or api enabled
if not self.api or api then
ngx.ctx.data[key] = value
end
end
-- Add data (makes table value must be table)
function template:add(key, value, api)
if not self.api or api then
if not ngx.ctx.data[key] then
ngx.ctx.data[key] = {}
elseif type(ngx.ctx.data[key]) ~= 'table' then
ngx.ctx.data[key] = { ngx.ctx.data[key] }
end
for k, v in pairs(value) do
table.insert(ngx.ctx.data[key], v)
end
end
end
-- Get data (dump all when no key)
function template:get(key)
if not key then return ngx.ctx.data end
return ngx.ctx.data[key]
end
-- Clear data
function template:clear()
ngx.ctx.data = {}
end
-- Set api on/off
function template:setApi(bool)
ngx.ctx.api = bool
end
-- Add raw code to current output
function template:put(content)
if self.api then return end
ngx.ctx.response = ngx.ctx.response .. tostring(content)
end
-- Load a lhtml file, convert code to lua, run and add string to end of response.content
function template:load(file, inline)
if self.api then return true end
--try cache
if self.caching and self.cache[file] then
return self:processFunction(self.cache[file], file)
end
--process string lhtml => lua
string = self:processFile(file)
--compile our string
local func, err = loadstring(string)
if not func then
if self.config.dir == 'luawa/' then
self:error(500, 'Template: ' .. file .. ' :: ' .. err)
else
luawa:error(500, 'Template: ' .. file .. ' :: ' .. err)
end
end
--save to cache
self.cache[file] = func
--run it
return self:processFunction(func, file)
end
-- Run a function
function template:processFunction(func, file)
--call the function safely
local env = _G
env.self = self
env.luawa = luawa
for k, v in pairs(self.env) do
env[k] = v
end
setfenv(func, env)
local status, err = pcall(func)
--if ok, add to output
if status then
if inline then
return err
else
ngx.ctx.response = ngx.ctx.response .. err
return true
end
else
if self.config.dir == 'luawa' then
return self:error(500, (file .. '.lhtml' or 'unkown') .. ' :: ' .. err)
else
return luawa:error(500, 'Template: ' .. (file or 'unkown') .. ' :: ' .. err)
end
end
end
--function to work before tostring
function template:toString(string)
--nil returns blank
if string == nil then return '' end
--string as string
if type(string) == 'string' then return self.utils.html_ents(string) end
--otherwise as best
return tostring(string)
end
--turn file => lua
function template:processFile(file)
local code
if self.config.dir == 'luawa' then
code = require('luawa.template.' .. file)
else
--read template file
local f, err = io.open(luawa.root .. self.config.dir .. file .. '.lhtml', 'r')
if not f then return luawa:error(500, 'Template: ' .. file .. ' :: Cant open/access file: ' .. err) end
--read the file
code, err = f:read('*a')
if not code then return luawa:error(500, 'Template: ' .. file .. ' :: File read error: ' .. err) end
--close file
f:close()
end
--minimize html? will probably break javascript!
if self.config.minimize then code = code:gsub('%s+', ' ') end
--prepend bits
code = 'local _output = "" _output = _output .. [[' .. code
--replace <?=vars?>
code = code:gsub('<%?=([#{},/_%+\'%[%]%:%.%a%s%d%(%)%*]+)%s%?>', ']] .. self:toString(%1) .. [[')
--replace <??=vars?>
code = code:gsub('<%?%?=([#{},/_%+\'%[%]%:%.%a%s%d%(%)%*]+)%s%?>', ']] .. %1 .. [[')
--replace <? to close output, start raw lua
code = code:gsub('<%?', ']] ')
--replace ?> to stop lua and start output (in table)
code = code:gsub('%?>', ' _output = _output .. [[')
--close final output and return concat of the table
local name = '\n--luawa_file:' .. file .. '\n'
code = code .. ' ]]\n' .. name .. '\nreturn _output'
return code
end
-- Emergency exit for errors in Luawa's templates!
function template:error(status, err)
ngx.header['Content-Type'] = 'text/plain'
ngx.say('Template error:')
ngx.say(err)
ngx.exit(status)
end
return template