mirror of
https://github.com/bjc/prosody.git
synced 2025-04-01 20:27:39 +03:00
170 lines
4 KiB
Lua
170 lines
4 KiB
Lua
local id = require "prosody.util.id";
|
|
|
|
local util_debug; -- only imported on-demand
|
|
|
|
-- Library configuration (see configure())
|
|
local auto_inject_traceback = false;
|
|
|
|
local error_mt = { __name = "error" };
|
|
|
|
function error_mt:__tostring()
|
|
return ("error<%s:%s:%s>"):format(self.type, self.condition, self.text or "");
|
|
end
|
|
|
|
local function is_error(e)
|
|
return getmetatable(e) == error_mt;
|
|
end
|
|
|
|
local function configure(opt)
|
|
if opt.auto_inject_traceback ~= nil then
|
|
auto_inject_traceback = opt.auto_inject_traceback;
|
|
if auto_inject_traceback then
|
|
util_debug = require "prosody.util.debug";
|
|
end
|
|
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)
|
|
if is_error(e) then return e; end
|
|
local template = registry and registry[e];
|
|
if not template then
|
|
if type(e) == "table" then
|
|
template = {
|
|
code = e.code;
|
|
type = e.type;
|
|
condition = e.condition;
|
|
text = e.text;
|
|
extra = e.extra;
|
|
};
|
|
else
|
|
template = {};
|
|
end
|
|
end
|
|
context = context or {};
|
|
|
|
if auto_inject_traceback then
|
|
context.traceback = util_debug.get_traceback_table(nil, 2);
|
|
end
|
|
|
|
local error_instance = setmetatable({
|
|
instance_id = id.short();
|
|
|
|
type = template.type or "cancel";
|
|
condition = template.condition or "undefined-condition";
|
|
text = template.text;
|
|
code = template.code;
|
|
extra = template.extra;
|
|
|
|
context = context;
|
|
source = source;
|
|
}, error_mt);
|
|
|
|
return error_instance;
|
|
end
|
|
|
|
-- compact --> normal form
|
|
local function expand_registry(namespace, registry)
|
|
local mapped = {}
|
|
for err,template in pairs(registry) do
|
|
local e = {
|
|
type = template[1];
|
|
condition = template[2];
|
|
text = template[3];
|
|
};
|
|
if namespace and template[4] then
|
|
e.extra = { namespace = namespace, condition = template[4] };
|
|
end
|
|
mapped[err] = e;
|
|
end
|
|
return mapped;
|
|
end
|
|
|
|
local function init(source, namespace, registry)
|
|
if type(namespace) == "table" then
|
|
-- registry can be given as second argument if namespace is not used
|
|
registry, namespace = namespace, nil;
|
|
end
|
|
local _, protoerr = next(registry, nil);
|
|
if protoerr and type(next(protoerr)) == "number" then
|
|
registry = expand_registry(namespace, registry);
|
|
end
|
|
|
|
local function wrap(e, context)
|
|
if is_error(e) then
|
|
return e;
|
|
end
|
|
local err = new(registry[e] or {
|
|
type = "cancel", condition = "undefined-condition"
|
|
}, context, registry, source);
|
|
err.context.wrapped_error = e;
|
|
return err;
|
|
end
|
|
|
|
return {
|
|
source = source;
|
|
registry = registry;
|
|
new = function (e, context)
|
|
return new(e, context, registry, source);
|
|
end;
|
|
coerce = function (ok, err, ...)
|
|
if ok then
|
|
return ok, err, ...;
|
|
end
|
|
return nil, wrap(err);
|
|
end;
|
|
wrap = wrap;
|
|
is_error = is_error;
|
|
};
|
|
end
|
|
|
|
local function coerce(ok, err, ...)
|
|
if ok or is_error(err) then
|
|
return ok, err, ...;
|
|
end
|
|
|
|
local new_err = new({
|
|
type = "cancel", condition = "undefined-condition"
|
|
}, { wrapped_error = err });
|
|
|
|
return ok, new_err, ...;
|
|
end
|
|
|
|
local function from_stanza(stanza, context, source)
|
|
local error_type, condition, text, extra_tag = stanza:get_error();
|
|
local error_tag = stanza:get_child("error");
|
|
context = context or {};
|
|
context.stanza = stanza;
|
|
context.by = error_tag and error_tag.attr.by or stanza.attr.from;
|
|
|
|
local uri;
|
|
if condition == "gone" or condition == "redirect" then
|
|
uri = error_tag:get_child_text(condition, "urn:ietf:params:xml:ns:xmpp-stanzas");
|
|
end
|
|
|
|
return new({
|
|
type = error_type or "cancel";
|
|
condition = condition or "undefined-condition";
|
|
text = text;
|
|
extra = (extra_tag or uri) and {
|
|
uri = uri;
|
|
tag = extra_tag;
|
|
} or nil;
|
|
}, context, nil, source);
|
|
end
|
|
|
|
return {
|
|
new = new;
|
|
init = init;
|
|
coerce = coerce;
|
|
is_error = is_error;
|
|
is_err = is_error; -- COMPAT w/ older 0.12 trunk
|
|
from_stanza = from_stanza;
|
|
configure = configure;
|
|
}
|