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 table = require "table"
|
||||||
local string = require "string"
|
local string = require "string"
|
||||||
local config = require "luci.config"
|
local config = require "luci.config"
|
||||||
local coroutine = require "coroutine"
|
|
||||||
local nixio = require "nixio", require "nixio.util"
|
local nixio = require "nixio", require "nixio.util"
|
||||||
local tparser = require "luci.template.parser"
|
local tparser = require "luci.template.parser"
|
||||||
|
|
||||||
|
@ -43,84 +42,12 @@ local assert, type, error = assert, type, error
|
||||||
module "luci.template"
|
module "luci.template"
|
||||||
|
|
||||||
config.template = config.template or {}
|
config.template = config.template or {}
|
||||||
|
|
||||||
viewdir = config.template.viewdir or util.libpath() .. "/view"
|
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"
|
|
||||||
|
|
||||||
|
|
||||||
-- Define the namespace for template modules
|
-- Define the namespace for template modules
|
||||||
context = util.threadlocal()
|
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.
|
--- Render a certain template.
|
||||||
-- @param name Template name
|
-- @param name Template name
|
||||||
-- @param scope Scope to assign to template (optional)
|
-- @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
|
-- Constructor - Reads and compiles the template on-demand
|
||||||
function Template.__init__(self, name)
|
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.template = self.cache[name]
|
||||||
self.name = name
|
self.name = name
|
||||||
|
@ -161,54 +73,11 @@ function Template.__init__(self, name)
|
||||||
self.viewns = context.viewns
|
self.viewns = context.viewns
|
||||||
|
|
||||||
-- If we have a cached template, skip compiling and loading
|
-- If we have a cached template, skip compiling and loading
|
||||||
if self.template then
|
if not self.template then
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Enforce cache security
|
-- Compile template
|
||||||
local cdir = compiledir .. "/" .. sys.process.info("uid")
|
local sourcefile = viewdir .. "/" .. name .. ".htm"
|
||||||
|
self.template, _, err = tparser.parse(sourcefile)
|
||||||
-- 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 we have no valid template throw error, otherwise cache the template
|
||||||
if not self.template then
|
if not self.template then
|
||||||
|
@ -217,6 +86,7 @@ function Template.__init__(self, name)
|
||||||
self.cache[name] = self.template
|
self.cache[name] = self.template
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Renders a template
|
-- Renders a template
|
||||||
|
|
|
@ -21,8 +21,4 @@ config internal sauth
|
||||||
config internal ccache
|
config internal ccache
|
||||||
option enable 1
|
option enable 1
|
||||||
|
|
||||||
config internal template
|
|
||||||
option compiler_mode memory
|
|
||||||
option compiledir "/tmp/luci-templatecache"
|
|
||||||
|
|
||||||
config internal themes
|
config internal themes
|
||||||
|
|
Loading…
Reference in a new issue