util/template.lua
author Matthew Wild <mwild1@gmail.com>
Fri, 23 Feb 2018 15:30:00 +0000
changeset 8531 67311cda0625
parent 8421 ad1e10c93b41
child 8558 4f0f5b49bb03
permissions -rw-r--r--
net.server_select: Better detection of errors for outgoing connections On connection failure, a socket is marked readable and writable. So to detect initial connection failures (connection refused, etc.) we now watch for sockets becoming readable during initial connection, and also read from readable sockets before writing to writable sockets. This should fix 'onconnect' being called for outgoing connections that actually failed.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
7199
94ec474debf5 util.template: Silence luacheck warnings about unused loop vars
Kim Alvefur <zash@zash.se>
parents: 6780
diff changeset
     1
-- luacheck: ignore 213/i
5214
1430c6f36621 util.template: Use util.xml.
Waqas Hussain <waqas20@gmail.com>
parents: 4495
diff changeset
     2
local stanza_mt = require "util.stanza".stanza_mt;
3545
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
     3
local setmetatable = setmetatable;
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
     4
local pairs = pairs;
3637
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
     5
local ipairs = ipairs;
3545
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
     6
local error = error;
8421
ad1e10c93b41 util.template: Use util.envload instead of loadstring which is deprecated in Lua 5.2
Kim Alvefur <zash@zash.se>
parents: 7200
diff changeset
     7
local envload = require "util.envload".envload;
3637
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
     8
local debug = debug;
4495
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
     9
local t_remove = table.remove;
5214
1430c6f36621 util.template: Use util.xml.
Waqas Hussain <waqas20@gmail.com>
parents: 4495
diff changeset
    10
local parse_xml = require "util.xml".parse;
3545
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    11
6780
5de6b93d0190 util.*: Remove use of module() function, make all module functions local and return them in a table at the end
Kim Alvefur <zash@zash.se>
parents: 5214
diff changeset
    12
local _ENV = nil;
3545
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    13
4495
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
    14
local function trim_xml(stanza)
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
    15
	for i=#stanza,1,-1 do
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
    16
		local child = stanza[i];
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
    17
		if child.name then
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
    18
			trim_xml(child);
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
    19
		else
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
    20
			child = child:gsub("^%s*", ""):gsub("%s*$", "");
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
    21
			stanza[i] = child;
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
    22
			if child == "" then t_remove(stanza, i); end
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
    23
		end
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
    24
	end
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
    25
end
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
    26
3637
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    27
local function create_string_string(str)
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    28
	str = ("%q"):format(str);
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    29
	str = str:gsub("{([^}]*)}", function(s)
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    30
		return '"..(data["'..s..'"]or"").."';
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    31
	end);
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    32
	return str;
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    33
end
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    34
local function create_attr_string(attr, xmlns)
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    35
	local str = '{';
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    36
	for name,value in pairs(attr) do
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    37
		if name ~= "xmlns" or value ~= xmlns then
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    38
			str = str..("[%q]=%s;"):format(name, create_string_string(value));
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    39
		end
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    40
	end
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    41
	return str..'}';
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    42
end
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    43
local function create_clone_string(stanza, lookup, xmlns)
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    44
	if not lookup[stanza] then
3640
4bc88bb748d1 util.template: Don't add stanza.last_add. 20% faster.
Waqas Hussain <waqas20@gmail.com>
parents: 3637
diff changeset
    45
		local s = ('setmetatable({name=%q,attr=%s,tags={'):format(stanza.name, create_attr_string(stanza.attr, xmlns));
3637
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    46
		-- add tags
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    47
		for i,tag in ipairs(stanza.tags) do
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    48
			s = s..create_clone_string(tag, lookup, stanza.attr.xmlns)..";";
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    49
		end
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    50
		s = s..'};';
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    51
		-- add children
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    52
		for i,child in ipairs(stanza) do
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    53
			if child.name then
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    54
				s = s..create_clone_string(child, lookup, stanza.attr.xmlns)..";";
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    55
			else
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    56
				s = s..create_string_string(child)..";"
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    57
			end
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    58
		end
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    59
		s = s..'}, stanza_mt)';
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    60
		s = s:gsub('%.%.""', ""):gsub('([=;])""%.%.', "%1"):gsub(';"";', ";"); -- strip empty strings
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    61
		local n = #lookup + 1;
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    62
		lookup[n] = s;
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    63
		lookup[stanza] = "_"..n;
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    64
	end
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    65
	return lookup[stanza];
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    66
end
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    67
local function create_cloner(stanza, chunkname)
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    68
	local lookup = {};
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    69
	local name = create_clone_string(stanza, lookup, "");
7200
ff514c1b1c27 util.template: Use separate variables for source and compiled function [luacheck]
Kim Alvefur <zash@zash.se>
parents: 7199
diff changeset
    70
	local src = "local setmetatable,stanza_mt=...;return function(data)";
3637
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    71
	for i=1,#lookup do
7200
ff514c1b1c27 util.template: Use separate variables for source and compiled function [luacheck]
Kim Alvefur <zash@zash.se>
parents: 7199
diff changeset
    72
		src = src.."local _"..i.."="..lookup[i]..";";
3546
cb1600dea3ad util.template: Optimized to be almost as fast as manual stanza building.
Waqas Hussain <waqas20@gmail.com>
parents: 3545
diff changeset
    73
	end
7200
ff514c1b1c27 util.template: Use separate variables for source and compiled function [luacheck]
Kim Alvefur <zash@zash.se>
parents: 7199
diff changeset
    74
	src = src.."return "..name..";end";
8421
ad1e10c93b41 util.template: Use util.envload instead of loadstring which is deprecated in Lua 5.2
Kim Alvefur <zash@zash.se>
parents: 7200
diff changeset
    75
	local f,err = envload(src, chunkname);
3637
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    76
	if not f then error(err); end
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    77
	return f(setmetatable, stanza_mt);
3546
cb1600dea3ad util.template: Optimized to be almost as fast as manual stanza building.
Waqas Hussain <waqas20@gmail.com>
parents: 3545
diff changeset
    78
end
cb1600dea3ad util.template: Optimized to be almost as fast as manual stanza building.
Waqas Hussain <waqas20@gmail.com>
parents: 3545
diff changeset
    79
3637
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    80
local template_mt = { __tostring = function(t) return t.name end };
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    81
local function create_template(templates, text)
3545
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    82
	local stanza, err = parse_xml(text);
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    83
	if not stanza then error(err); end
4495
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
    84
	trim_xml(stanza);
3637
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    85
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    86
	local info = debug.getinfo(3, "Sl");
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    87
	info = info and ("template(%s:%d)"):format(info.short_src:match("[^\\/]*$"), info.currentline) or "template(unknown)";
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    88
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    89
	local template = setmetatable({ apply = create_cloner(stanza, info), name = info, text = text }, template_mt);
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    90
	templates[text] = template;
3545
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    91
	return template;
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    92
end
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    93
3637
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    94
local templates = setmetatable({}, { __mode = 'k', __index = create_template });
3545
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    95
return function(text)
3637
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
    96
	return templates[text];
3545
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    97
end;