Software /
code /
prosody
File
util/error.lua @ 12630:781772c8b6d9
mod_mam: Store archives with sub-second precision timestamps
Changes sub-second part of example timestamp to .5 in order to avoid
floating point issues.
Some clients use timestamps when ordering messages which can lead to
messages having the same timestamp ending up in the wrong order.
It would be better to preserve the order messages are sent in, which is
the order they were stored in.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Sun, 14 Aug 2022 17:28:31 +0200 (2022-08-14) |
parent | 11224:8143fd2f138b |
child | 12975:d10957394a3c |
child | 13078:6da83deb8d7f |
line wrap: on
line source
local id = require "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 "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.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; }