libs/web: drop the Lua template parser, the C implementation is faster in almost every case, even without caching
This commit is contained in:
parent
d32f3dca5c
commit
aa93e16092
2 changed files with 12 additions and 146 deletions
|
@ -30,7 +30,6 @@ local util = require "luci.util"
|
|||
local table = require "table"
|
||||
local string = require "string"
|
||||
local config = require "luci.config"
|
||||
local coroutine = require "coroutine"
|
||||
local nixio = require "nixio", require "nixio.util"
|
||||
local tparser = require "luci.template.parser"
|
||||
|
||||
|
@ -43,84 +42,12 @@ local assert, type, error = assert, type, error
|
|||
module "luci.template"
|
||||
|
||||
config.template = config.template or {}
|
||||
|
||||
viewdir = config.template.viewdir or util.libpath() .. "/view"
|
||||
compiledir = config.template.compiledir or util.libpath() .. "/view"
|
||||
|
||||
|
||||
-- Compile modes:
|
||||
-- memory: Always compile, do not save compiled files, ignore precompiled
|
||||
-- file: Compile on demand, save compiled files, update precompiled
|
||||
compiler_mode = config.template.compiler_mode or "memory"
|
||||
viewdir = config.template.viewdir or util.libpath() .. "/view"
|
||||
|
||||
|
||||
-- Define the namespace for template modules
|
||||
context = util.threadlocal()
|
||||
|
||||
--- Manually compile a given template into an executable Lua function
|
||||
-- @param template LuCI template
|
||||
-- @return Lua template function
|
||||
function compile(template)
|
||||
local expr = {}
|
||||
|
||||
-- Search all <% %> expressions
|
||||
local function expr_add(ws1, skip1, command, skip2, ws2)
|
||||
expr[#expr+1] = command
|
||||
return ( #skip1 > 0 and "" or ws1 ) ..
|
||||
"<%" .. tostring(#expr) .. "%>" ..
|
||||
( #skip2 > 0 and "" or ws2 )
|
||||
end
|
||||
|
||||
-- Save all expressiosn to table "expr"
|
||||
template = template:gsub("(%s*)<%%(%-?)(.-)(%-?)%%>(%s*)", expr_add)
|
||||
|
||||
local function sanitize(s)
|
||||
s = "%q" % s
|
||||
return s:sub(2, #s-1)
|
||||
end
|
||||
|
||||
-- Escape and sanitize all the template (all non-expressions)
|
||||
template = sanitize(template)
|
||||
|
||||
-- Template module header/footer declaration
|
||||
local header = 'write("'
|
||||
local footer = '")'
|
||||
|
||||
template = header .. template .. footer
|
||||
|
||||
-- Replacements
|
||||
local r_include = '")\ninclude("%s")\nwrite("'
|
||||
local r_i18n = '")\nwrite(translate("%1","%2"))\nwrite("'
|
||||
local r_i18n2 = '")\nwrite(translate("%1", ""))\nwrite("'
|
||||
local r_pexec = '")\nwrite(tostring(%s or ""))\nwrite("'
|
||||
local r_exec = '")\n%s\nwrite("'
|
||||
|
||||
-- Parse the expressions
|
||||
for k,v in pairs(expr) do
|
||||
local p = v:sub(1, 1)
|
||||
v = v:gsub("%%", "%%%%")
|
||||
local re = nil
|
||||
if p == "+" then
|
||||
re = r_include:format(sanitize(string.sub(v, 2)))
|
||||
elseif p == ":" then
|
||||
if v:find(" ") then
|
||||
re = sanitize(v):gsub(":(.-) (.*)", r_i18n)
|
||||
else
|
||||
re = sanitize(v):gsub(":(.+)", r_i18n2)
|
||||
end
|
||||
elseif p == "=" then
|
||||
re = r_pexec:format(v:sub(2))
|
||||
elseif p == "#" then
|
||||
re = ""
|
||||
else
|
||||
re = r_exec:format(v)
|
||||
end
|
||||
template = template:gsub("<%%"..tostring(k).."%%>", re)
|
||||
end
|
||||
|
||||
return loadstring(template)
|
||||
end
|
||||
|
||||
--- Render a certain template.
|
||||
-- @param name Template name
|
||||
-- @param scope Scope to assign to template (optional)
|
||||
|
@ -138,21 +65,6 @@ Template.cache = setmetatable({}, {__mode = "v"})
|
|||
|
||||
-- Constructor - Reads and compiles the template on-demand
|
||||
function Template.__init__(self, name)
|
||||
local function _encode_filename(str)
|
||||
|
||||
local function __chrenc( chr )
|
||||
return "%%%02x" % string.byte( chr )
|
||||
end
|
||||
|
||||
if type(str) == "string" then
|
||||
str = str:gsub(
|
||||
"([^a-zA-Z0-9$_%-%.%+!*'(),])",
|
||||
__chrenc
|
||||
)
|
||||
end
|
||||
|
||||
return str
|
||||
end
|
||||
|
||||
self.template = self.cache[name]
|
||||
self.name = name
|
||||
|
@ -161,60 +73,18 @@ function Template.__init__(self, name)
|
|||
self.viewns = context.viewns
|
||||
|
||||
-- If we have a cached template, skip compiling and loading
|
||||
if self.template then
|
||||
return
|
||||
end
|
||||
|
||||
-- Enforce cache security
|
||||
local cdir = compiledir .. "/" .. sys.process.info("uid")
|
||||
|
||||
-- Compile and build
|
||||
local sourcefile = viewdir .. "/" .. name
|
||||
local compiledfile = cdir .. "/" .. _encode_filename(name) .. ".lua"
|
||||
local err
|
||||
|
||||
if compiler_mode == "file" then
|
||||
local tplmt = fs.stat(sourcefile, "mtime") or fs.stat(sourcefile .. ".htm", "mtime")
|
||||
local commt = fs.stat(compiledfile, "mtime")
|
||||
|
||||
if not fs.stat(cdir, "mtime") then
|
||||
fs.mkdirr(cdir)
|
||||
fs.chmod(fs.dirname(cdir), 777)
|
||||
end
|
||||
|
||||
assert(tplmt or commt, "No such template: " .. name)
|
||||
|
||||
-- Build if there is no compiled file or if compiled file is outdated
|
||||
if not commt or (commt and tplmt and commt < tplmt) then
|
||||
local source
|
||||
source, err = fs.readfile(sourcefile) or fs.readfile(sourcefile .. ".htm")
|
||||
|
||||
if source then
|
||||
local compiled, err = compile(source)
|
||||
|
||||
local f = nixio.open(compiledfile, "w", 600)
|
||||
f:writeall(util.get_bytecode(compiled))
|
||||
f:close()
|
||||
self.template = compiled
|
||||
end
|
||||
else
|
||||
assert(
|
||||
sys.process.info("uid") == fs.stat(compiledfile, "uid")
|
||||
and fs.stat(compiledfile, "modestr") == "rw-------",
|
||||
"Fatal: Cachefile is not sane!"
|
||||
)
|
||||
self.template, err = loadfile(compiledfile)
|
||||
end
|
||||
|
||||
elseif compiler_mode == "memory" then
|
||||
self.template, _, err = tparser.parse(sourcefile .. ".htm")
|
||||
end
|
||||
|
||||
-- If we have no valid template throw error, otherwise cache the template
|
||||
if not self.template then
|
||||
error(err)
|
||||
else
|
||||
self.cache[name] = self.template
|
||||
|
||||
-- Compile template
|
||||
local sourcefile = viewdir .. "/" .. name .. ".htm"
|
||||
self.template, _, err = tparser.parse(sourcefile)
|
||||
|
||||
-- If we have no valid template throw error, otherwise cache the template
|
||||
if not self.template then
|
||||
error(err)
|
||||
else
|
||||
self.cache[name] = self.template
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -20,9 +20,5 @@ config internal sauth
|
|||
|
||||
config internal ccache
|
||||
option enable 1
|
||||
|
||||
config internal template
|
||||
option compiler_mode memory
|
||||
option compiledir "/tmp/luci-templatecache"
|
||||
|
||||
config internal themes
|
||||
|
|
Loading…
Reference in a new issue