Software /
code /
prosody
Comparison
util/error.lua @ 11200:bf8f2da84007
Merge 0.11->trunk
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Thu, 05 Nov 2020 22:31:25 +0100 |
parent | 11161:f51ed2652602 |
child | 11207:4e060ae8520b |
comparison
equal
deleted
inserted
replaced
11199:6c7c50a4de32 | 11200:bf8f2da84007 |
---|---|
1 local id = require "util.id"; | |
2 | |
3 -- Library configuration (see configure()) | |
4 local auto_inject_traceback = false; | |
5 local display_tracebacks = false; | |
6 | |
7 | |
8 local error_mt = { __name = "error" }; | |
9 | |
10 function error_mt:__tostring() | |
11 if display_tracebacks and self.context.traceback then | |
12 return ("error<%s:%s:%s:%s>"):format(self.type, self.condition, self.text or "", self.context.traceback); | |
13 end | |
14 return ("error<%s:%s:%s>"):format(self.type, self.condition, self.text or ""); | |
15 end | |
16 | |
17 local function is_err(e) | |
18 return getmetatable(e) == error_mt; | |
19 end | |
20 | |
21 local function configure(opt) | |
22 if opt.display_tracebacks ~= nil then | |
23 display_tracebacks = opt.display_tracebacks; | |
24 end | |
25 if opt.auto_inject_traceback ~= nil then | |
26 auto_inject_traceback = opt.auto_inject_traceback; | |
27 end | |
28 end | |
29 | |
30 -- Do we want any more well-known fields? | |
31 -- Or could we just copy all fields from `e`? | |
32 -- Sometimes you want variable details in the `text`, how to handle that? | |
33 -- Translations? | |
34 -- Should the `type` be restricted to the stanza error types or free-form? | |
35 -- What to set `type` to for stream errors or SASL errors? Those don't have a 'type' attr. | |
36 | |
37 local function new(e, context, registry, source) | |
38 if is_err(e) then return e; end | |
39 local template = registry and registry[e]; | |
40 if not template then | |
41 if type(e) == "table" then | |
42 template = { | |
43 code = e.code; | |
44 type = e.type; | |
45 condition = e.condition; | |
46 text = e.text; | |
47 extra = e.extra; | |
48 }; | |
49 else | |
50 template = {}; | |
51 end | |
52 end | |
53 context = context or {}; | |
54 | |
55 if auto_inject_traceback then | |
56 context.traceback = debug.traceback("error stack", 2); | |
57 end | |
58 | |
59 local error_instance = setmetatable({ | |
60 instance_id = id.short(); | |
61 | |
62 type = template.type or "cancel"; | |
63 condition = template.condition or "undefined-condition"; | |
64 text = template.text; | |
65 code = template.code; | |
66 extra = template.extra; | |
67 | |
68 context = context; | |
69 source = source; | |
70 }, error_mt); | |
71 | |
72 return error_instance; | |
73 end | |
74 | |
75 -- compact --> normal form | |
76 local function expand_registry(namespace, registry) | |
77 local mapped = {} | |
78 for err,template in pairs(registry) do | |
79 local e = { | |
80 type = template[1]; | |
81 condition = template[2]; | |
82 text = template[3]; | |
83 }; | |
84 if namespace and template[4] then | |
85 e.extra = { namespace = namespace, condition = template[4] }; | |
86 end | |
87 mapped[err] = e; | |
88 end | |
89 return mapped; | |
90 end | |
91 | |
92 local function init(source, namespace, registry) | |
93 if type(namespace) == "table" then | |
94 -- registry can be given as second argument if namespace is either not used | |
95 registry, namespace = namespace, nil; | |
96 end | |
97 local _, protoerr = next(registry, nil); | |
98 if protoerr and type(next(protoerr)) == "number" then | |
99 registry = expand_registry(namespace, registry); | |
100 end | |
101 return { | |
102 source = source; | |
103 registry = registry; | |
104 new = function (e, context) | |
105 return new(e, context, registry, source); | |
106 end; | |
107 }; | |
108 end | |
109 | |
110 local function coerce(ok, err, ...) | |
111 if ok or is_err(err) then | |
112 return ok, err, ...; | |
113 end | |
114 | |
115 local new_err = new({ | |
116 type = "cancel", condition = "undefined-condition" | |
117 }, { wrapped_error = err }); | |
118 | |
119 return ok, new_err, ...; | |
120 end | |
121 | |
122 local function from_stanza(stanza, context, source) | |
123 local error_type, condition, text, extra_tag = stanza:get_error(); | |
124 local error_tag = stanza:get_child("error"); | |
125 context = context or {}; | |
126 context.stanza = stanza; | |
127 context.by = error_tag.attr.by or stanza.attr.from; | |
128 | |
129 local uri; | |
130 if condition == "gone" or condition == "redirect" then | |
131 uri = error_tag:get_child_text(condition, "urn:ietf:params:xml:ns:xmpp-stanzas"); | |
132 end | |
133 | |
134 return new({ | |
135 type = error_type or "cancel"; | |
136 condition = condition or "undefined-condition"; | |
137 text = text; | |
138 extra = (extra_tag or uri) and { | |
139 uri = uri; | |
140 tag = extra_tag; | |
141 } or nil; | |
142 }, context, nil, source); | |
143 end | |
144 | |
145 return { | |
146 new = new; | |
147 init = init; | |
148 coerce = coerce; | |
149 is_err = is_err; | |
150 from_stanza = from_stanza; | |
151 configure = configure; | |
152 } |