aboutsummaryrefslogtreecommitdiffstats
path: root/util/error.lua
diff options
context:
space:
mode:
Diffstat (limited to 'util/error.lua')
-rw-r--r--util/error.lua93
1 files changed, 93 insertions, 0 deletions
diff --git a/util/error.lua b/util/error.lua
new file mode 100644
index 00000000..c46f8790
--- /dev/null
+++ b/util/error.lua
@@ -0,0 +1,93 @@
+
+-- 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;
+}