diff options
author | Kim Alvefur <zash@zash.se> | 2018-12-28 20:51:31 +0100 |
---|---|---|
committer | Kim Alvefur <zash@zash.se> | 2018-12-28 20:51:31 +0100 |
commit | 5806d67e82705701d6b778d4b6399724a035c528 (patch) | |
tree | 5cefd934daf61742627bf79c6582fbcc3b6903b1 | |
parent | b250ff0d70b614a5ee0025fc68f175428bfca4b5 (diff) | |
download | prosody-5806d67e82705701d6b778d4b6399724a035c528.tar.gz prosody-5806d67e82705701d6b778d4b6399724a035c528.zip |
core.moduleapi: Add a promise-based API for tracking IQ stanzas (fixes #714)
-rw-r--r-- | core/moduleapi.lua | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/core/moduleapi.lua b/core/moduleapi.lua index d2aa1e8c..f7aa7216 100644 --- a/core/moduleapi.lua +++ b/core/moduleapi.lua @@ -361,6 +361,71 @@ function api:send(stanza, origin) return core_post_stanza(origin or hosts[self.host], stanza); end +function api:send_iq(stanza, origin, timeout) + local iq_cache = self._iq_cache; + if not iq_cache then + iq_cache = require "util.cache".new(256, function (_, iq) + iq.reject("evicted"); + self:unhook(iq.result_event, iq.result_handler); + self:unhook(iq.error_event, iq.error_handler); + end); + self._iq_cache = iq_cache; + end + return require "util.promise".new(function (resolve, reject) + local event_type; + if stanza.attr.from == self.host then + event_type = "host"; + else -- assume bare since we can't hook full jids + event_type = "bare"; + end + local result_event = "iq-result/"..event_type.."/"..stanza.attr.id; + local error_event = "iq-error/"..event_type.."/"..stanza.attr.id; + local cache_key = event_type.."/"..stanza.attr.id; + + local function result_handler(event) + if event.stanza.attr.from == stanza.attr.to then + resolve(event); + return true; + end + end + + local function error_handler(event) + if event.stanza.attr.from == stanza.attr.to then + reject(event); + return true; + end + end + + if iq_cache:get(cache_key) then + error("choose another iq stanza id attribute") + end + + self:hook(result_event, result_handler); + self:hook(error_event, error_handler); + + local timeout_handle = self:add_timer(timeout or 120, function () + reject("timeout"); + self:unhook(result_event, result_handler); + self:unhook(error_event, error_handler); + iq_cache:set(cache_key, nil); + end); + + local ok = iq_cache:set(cache_key, { + reject = reject, resolve = resolve, + timeout_handle = timeout_handle, + result_event = result_event, error_event = error_event, + result_handler = result_handler, error_handler = error_handler; + }); + + if not ok then + reject("cache insertion failure"); + return; + end + + self:send(stanza, origin); + end); +end + function api:broadcast(jids, stanza, iter) for jid in (iter or it.values)(jids) do local new_stanza = st.clone(stanza); |