File

util/error.lua @ 11056:0b0a42542456

util.jid: Fix special escaping of '\' per XEP-0106 From XEP-0106 §2. Requirements: > in certain circumstances, the escaping character itself ("\") might > also be escaped Later in §4.2 Address Transformation Algorithm it is stated that the backslash would only be escaped if it forms an escape sequence. Thus '\foo' is unaltered but '\20' must be escaped into '\5c20'. Thanks to lovetox and jonas’ for brining up.
author Kim Alvefur <zash@zash.se>
date Fri, 28 Aug 2020 18:44:02 +0200
parent 11054:ad07152d7bde
child 11075:d8fad2b48b05
line wrap: on
line source


-- Library configuration (see configure())
local auto_inject_traceback = false;
local display_tracebacks = false;


local error_mt = { __name = "error" };

function error_mt:__tostring()
	if display_tracebacks and self.context.traceback then
		return ("error<%s:%s:%s:%s>"):format(self.type, self.condition, self.text or "", self.context.traceback);
	end
	return ("error<%s:%s:%s>"):format(self.type, self.condition, self.text or "");
end

local function is_err(e)
	return getmetatable(e) == error_mt;
end

local function configure(opt)
	if opt.display_tracebacks ~= nil then
		display_tracebacks = opt.display_tracebacks;
	end
	if opt.auto_inject_traceback ~= nil then
		auto_inject_traceback = opt.auto_inject_traceback;
	end
end

-- Do we want any more well-known fields?
-- Or could we just copy all fields from `e`?
-- Sometimes you want variable details in the `text`, how to handle that?
-- Translations?
-- Should the `type` be restricted to the stanza error types or free-form?
-- What to set `type` to for stream errors or SASL errors? Those don't have a 'type' attr.

local function new(e, context, registry, source)
	local template = (registry and registry[e]) or e or {};
	context = context or template.context or { _error_id = e };

	if auto_inject_traceback then
		context.traceback = debug.traceback("error stack", 2);
	end

	return setmetatable({
		type = template.type or "cancel";
		condition = template.condition or "undefined-condition";
		text = template.text;
		code = template.code;

		context = context or template.context or { _error_id = e };
		source = source;
	}, error_mt);
end

local function init(source, registry)
	return function (e, context)
		return new(e, context, registry, source);
	end
end

local function coerce(ok, err, ...)
	if ok or is_err(err) then
		return ok, err, ...;
	end

	local new_err = setmetatable({
		native = err;

		type = "cancel";
		condition = "undefined-condition";
	}, error_mt);
	return ok, new_err, ...;
end

local function from_stanza(stanza, context)
	local error_type, condition, text = stanza:get_error();
	return setmetatable({
		type = error_type or "cancel";
		condition = condition or "undefined-condition";
		text = text;

		context = context or { stanza = stanza };
	}, error_mt);
end

return {
	new = new;
	init = init;
	coerce = coerce;
	is_err = is_err;
	from_stanza = from_stanza;
	configure = configure;
}