Mercurial > prosody-modules
comparison mod_cloud_notify/mod_cloud_notify.lua @ 3943:f5e6368a1c39
mod_cloud_notify: Cleanup code and drop support for prosody 0.9
This removes some legacy stuff that was needed for prosody 0.9
We now use util.stanza:find instead of our own patched version to be more mainstream
The unneeded module unloading code was removed, too
| author | tmolitor <thilo@eightysoft.de> |
|---|---|
| date | Wed, 11 Mar 2020 20:00:50 +0100 |
| parents | 675726ab06d3 |
| children | 6bf362008052 |
comparison
equal
deleted
inserted
replaced
| 3942:e93e58b33bf6 | 3943:f5e6368a1c39 |
|---|---|
| 12 local st = require"util.stanza"; | 12 local st = require"util.stanza"; |
| 13 local jid = require"util.jid"; | 13 local jid = require"util.jid"; |
| 14 local dataform = require"util.dataforms".new; | 14 local dataform = require"util.dataforms".new; |
| 15 local filters = require"util.filters"; | 15 local filters = require"util.filters"; |
| 16 local hashes = require"util.hashes"; | 16 local hashes = require"util.hashes"; |
| 17 local random = require"util.random"; | |
| 18 local cache = require"util.cache"; | |
| 17 | 19 |
| 18 local xmlns_push = "urn:xmpp:push:0"; | 20 local xmlns_push = "urn:xmpp:push:0"; |
| 19 | 21 |
| 20 -- configuration | 22 -- configuration |
| 21 local include_body = module:get_option_boolean("push_notification_with_body", false); | 23 local include_body = module:get_option_boolean("push_notification_with_body", false); |
| 25 local dummy_body = module:get_option_string("push_notification_important_body", "New Message!"); | 27 local dummy_body = module:get_option_string("push_notification_important_body", "New Message!"); |
| 26 | 28 |
| 27 local host_sessions = prosody.hosts[module.host].sessions; | 29 local host_sessions = prosody.hosts[module.host].sessions; |
| 28 local push_errors = {}; | 30 local push_errors = {}; |
| 29 local id2node = {}; | 31 local id2node = {}; |
| 30 | 32 local id2identifier = {}; |
| 31 -- ordered table iterator, allow to iterate on the natural order of the keys of a table, | |
| 32 -- see http://lua-users.org/wiki/SortedIteration | |
| 33 local function __genOrderedIndex( t ) | |
| 34 local orderedIndex = {} | |
| 35 for key in pairs(t) do | |
| 36 table.insert( orderedIndex, key ) | |
| 37 end | |
| 38 -- sort in reverse order (newest one first) | |
| 39 table.sort( orderedIndex, function(a, b) | |
| 40 if a == nil or t[a] == nil or b == nil or t[b] == nil then return false end | |
| 41 -- only one timestamp given, this is the newer one | |
| 42 if t[a].timestamp ~= nil and t[b].timestamp == nil then return true end | |
| 43 if t[a].timestamp == nil and t[b].timestamp ~= nil then return false end | |
| 44 -- both timestamps given, sort normally | |
| 45 if t[a].timestamp ~= nil and t[b].timestamp ~= nil then return t[a].timestamp > t[b].timestamp end | |
| 46 return false -- normally not reached | |
| 47 end) | |
| 48 return orderedIndex | |
| 49 end | |
| 50 local function orderedNext(t, state) | |
| 51 -- Equivalent of the next function, but returns the keys in timestamp | |
| 52 -- order. We use a temporary ordered key table that is stored in the | |
| 53 -- table being iterated. | |
| 54 | |
| 55 local key = nil | |
| 56 --print("orderedNext: state = "..tostring(state) ) | |
| 57 if state == nil then | |
| 58 -- the first time, generate the index | |
| 59 t.__orderedIndex = __genOrderedIndex( t ) | |
| 60 key = t.__orderedIndex[1] | |
| 61 else | |
| 62 -- fetch the next value | |
| 63 for i = 1, #t.__orderedIndex do | |
| 64 if t.__orderedIndex[i] == state then | |
| 65 key = t.__orderedIndex[i+1] | |
| 66 end | |
| 67 end | |
| 68 end | |
| 69 | |
| 70 if key then | |
| 71 return key, t[key] | |
| 72 end | |
| 73 | |
| 74 -- no more value to return, cleanup | |
| 75 t.__orderedIndex = nil | |
| 76 return | |
| 77 end | |
| 78 local function orderedPairs(t) | |
| 79 -- Equivalent of the pairs() function on tables. Allows to iterate | |
| 80 -- in order | |
| 81 return orderedNext, t, nil | |
| 82 end | |
| 83 | |
| 84 -- small helper function to return new table with only "maximum" elements containing only the newest entries | |
| 85 local function reduce_table(table, maximum) | |
| 86 local count = 0; | |
| 87 local result = {}; | |
| 88 for key, value in orderedPairs(table) do | |
| 89 count = count + 1; | |
| 90 if count > maximum then break end | |
| 91 result[key] = value; | |
| 92 end | |
| 93 return result; | |
| 94 end | |
| 95 | |
| 96 local function stoppable_timer(delay, callback) | |
| 97 local stopped = false; | |
| 98 local timer = module:add_timer(delay, function (t) | |
| 99 if stopped then return; end | |
| 100 return callback(t); | |
| 101 end); | |
| 102 if timer and timer.stop then return timer; end -- new prosody api includes stop() function | |
| 103 return { | |
| 104 stop = function(self) stopped = true end; | |
| 105 timer; | |
| 106 }; | |
| 107 end | |
| 108 | 33 |
| 109 -- For keeping state across reloads while caching reads | 34 -- For keeping state across reloads while caching reads |
| 35 -- This uses util.cache for caching the most recent devices and removing all old devices when max_push_devices is reached | |
| 110 local push_store = (function() | 36 local push_store = (function() |
| 111 local store = module:open_store(); | 37 local store = module:open_store(); |
| 112 local push_services = {}; | 38 local push_services = {}; |
| 113 local api = {}; | 39 local api = {}; |
| 114 function api:get(user) | 40 function api:get(user) |
| 115 if not push_services[user] then | 41 if not push_services[user] then |
| 116 local err; | 42 local loaded, err = store:get(user); |
| 117 push_services[user], err = store:get(user); | 43 if not loaded and err then |
| 118 if not push_services[user] and err then | |
| 119 module:log("warn", "Error reading push notification storage for user '%s': %s", user, tostring(err)); | 44 module:log("warn", "Error reading push notification storage for user '%s': %s", user, tostring(err)); |
| 120 push_services[user] = {}; | 45 push_services[user] = cache.new(max_push_devices):table(); |
| 121 return push_services[user], false; | 46 return push_services[user], false; |
| 122 end | 47 end |
| 123 end | 48 if loaded then |
| 124 if not push_services[user] then push_services[user] = {} end | 49 push_services[user] = cache.new(max_push_devices):table(); |
| 50 -- copy over plain table loaded from disk into our cache | |
| 51 for k, v in pairs(loaded) do push_services[user][k] = v; end | |
| 52 else | |
| 53 push_services[user] = cache.new(max_push_devices):table(); | |
| 54 end | |
| 55 end | |
| 125 return push_services[user], true; | 56 return push_services[user], true; |
| 126 end | 57 end |
| 127 function api:set(user, data) | 58 function api:flush_to_disk(user) |
| 128 push_services[user] = reduce_table(data, max_push_devices); | 59 local plain_table = {}; |
| 129 local ok, err = store:set(user, push_services[user]); | 60 for k, v in pairs(push_services[user]) do plain_table[k] = v; end |
| 61 local ok, err = store:set(user, plain_table); | |
| 130 if not ok then | 62 if not ok then |
| 131 module:log("error", "Error writing push notification storage for user '%s': %s", user, tostring(err)); | 63 module:log("error", "Error writing push notification storage for user '%s': %s", user, tostring(err)); |
| 132 return false; | 64 return false; |
| 133 end | 65 end |
| 134 return true; | 66 return true; |
| 135 end | 67 end |
| 136 function api:set_identifier(user, push_identifier, data) | 68 function api:set_identifier(user, push_identifier, data) |
| 137 local services = self:get(user); | 69 local services = self:get(user); |
| 138 services[push_identifier] = data; | 70 services[push_identifier] = data; |
| 139 return self:set(user, services); | |
| 140 end | 71 end |
| 141 return api; | 72 return api; |
| 142 end)(); | 73 end)(); |
| 143 | 74 |
| 144 | 75 |
| 147 | 78 |
| 148 function handle_push_error(event) | 79 function handle_push_error(event) |
| 149 local stanza = event.stanza; | 80 local stanza = event.stanza; |
| 150 local error_type, condition = stanza:get_error(); | 81 local error_type, condition = stanza:get_error(); |
| 151 local node = id2node[stanza.attr.id]; | 82 local node = id2node[stanza.attr.id]; |
| 83 local identifier = id2identifier[stanza.attr.id]; | |
| 152 if node == nil then return false; end -- unknown stanza? Ignore for now! | 84 if node == nil then return false; end -- unknown stanza? Ignore for now! |
| 153 local from = stanza.attr.from; | 85 local from = stanza.attr.from; |
| 154 local user_push_services = push_store:get(node); | 86 local user_push_services = push_store:get(node); |
| 155 local changed = false; | 87 local changed = false; |
| 156 | 88 |
| 157 for push_identifier, _ in pairs(user_push_services) do | 89 for push_identifier, _ in pairs(user_push_services) do |
| 158 local stanza_id = hashes.sha256(push_identifier, true); | 90 if push_identifier == identifier then |
| 159 if stanza_id == stanza.attr.id then | |
| 160 if user_push_services[push_identifier] and user_push_services[push_identifier].jid == from and error_type ~= "wait" then | 91 if user_push_services[push_identifier] and user_push_services[push_identifier].jid == from and error_type ~= "wait" then |
| 161 push_errors[push_identifier] = push_errors[push_identifier] + 1; | 92 push_errors[push_identifier] = push_errors[push_identifier] + 1; |
| 162 module:log("info", "Got error of type '%s' (%s) for identifier '%s': " | 93 module:log("info", "Got error of type '%s' (%s) for identifier '%s': " |
| 163 .."error count for this identifier is now at %s", error_type, condition, push_identifier, | 94 .."error count for this identifier is now at %s", error_type, condition, push_identifier, |
| 164 tostring(push_errors[push_identifier])); | 95 tostring(push_errors[push_identifier])); |
| 177 -- save changed global config | 108 -- save changed global config |
| 178 changed = true; | 109 changed = true; |
| 179 user_push_services[push_identifier] = nil | 110 user_push_services[push_identifier] = nil |
| 180 push_errors[push_identifier] = nil; | 111 push_errors[push_identifier] = nil; |
| 181 -- unhook iq handlers for this identifier (if possible) | 112 -- unhook iq handlers for this identifier (if possible) |
| 182 if module.unhook then | 113 module:unhook("iq-error/host/"..stanza.attr.id, handle_push_error); |
| 183 module:unhook("iq-error/host/"..stanza_id, handle_push_error); | 114 module:unhook("iq-result/host/"..stanza.attr.id, handle_push_success); |
| 184 module:unhook("iq-result/host/"..stanza_id, handle_push_success); | 115 id2node[stanza.attr.id] = nil; |
| 185 id2node[stanza_id] = nil; | 116 id2identifier[stanza.attr.id] = nil; |
| 186 end | |
| 187 end | 117 end |
| 188 elseif user_push_services[push_identifier] and user_push_services[push_identifier].jid == from and error_type == "wait" then | 118 elseif user_push_services[push_identifier] and user_push_services[push_identifier].jid == from and error_type == "wait" then |
| 189 module:log("debug", "Got error of type '%s' (%s) for identifier '%s': " | 119 module:log("debug", "Got error of type '%s' (%s) for identifier '%s': " |
| 190 .."NOT increasing error count for this identifier", error_type, condition, push_identifier); | 120 .."NOT increasing error count for this identifier", error_type, condition, push_identifier); |
| 191 end | 121 end |
| 192 end | 122 end |
| 193 end | 123 end |
| 194 if changed then | 124 if changed then |
| 195 push_store:set(node, user_push_services); | 125 push_store:flush_to_disk(node); |
| 196 end | 126 end |
| 197 return true; | 127 return true; |
| 198 end | 128 end |
| 199 | 129 |
| 200 function handle_push_success(event) | 130 function handle_push_success(event) |
| 201 local stanza = event.stanza; | 131 local stanza = event.stanza; |
| 202 local node = id2node[stanza.attr.id]; | 132 local node = id2node[stanza.attr.id]; |
| 133 local identifier = id2identifier[stanza.attr.id]; | |
| 203 if node == nil then return false; end -- unknown stanza? Ignore for now! | 134 if node == nil then return false; end -- unknown stanza? Ignore for now! |
| 204 local from = stanza.attr.from; | 135 local from = stanza.attr.from; |
| 205 local user_push_services = push_store:get(node); | 136 local user_push_services = push_store:get(node); |
| 206 | 137 |
| 207 for push_identifier, _ in pairs(user_push_services) do | 138 for push_identifier, _ in pairs(user_push_services) do |
| 208 if hashes.sha256(push_identifier, true) == stanza.attr.id then | 139 if push_identifier == identifier then |
| 209 if user_push_services[push_identifier] and user_push_services[push_identifier].jid == from and push_errors[push_identifier] > 0 then | 140 if user_push_services[push_identifier] and user_push_services[push_identifier].jid == from and push_errors[push_identifier] > 0 then |
| 210 push_errors[push_identifier] = 0; | 141 push_errors[push_identifier] = 0; |
| 211 -- unhook iq handlers for this identifier (if possible) | 142 -- unhook iq handlers for this identifier (if possible) |
| 212 if module.unhook then | 143 module:unhook("iq-error/host/"..stanza.attr.id, handle_push_error); |
| 213 module:unhook("iq-error/host/"..stanza.attr.id, handle_push_error); | 144 module:unhook("iq-result/host/"..stanza.attr.id, handle_push_success); |
| 214 module:unhook("iq-result/host/"..stanza.attr.id, handle_push_success); | 145 id2node[stanza.attr.id] = nil; |
| 215 id2node[stanza.attr.id] = nil; | 146 id2identifier[stanza.attr.id] = nil; |
| 216 end | |
| 217 module:log("debug", "Push succeeded, error count for identifier '%s' is now at %s again", push_identifier, tostring(push_errors[push_identifier])); | 147 module:log("debug", "Push succeeded, error count for identifier '%s' is now at %s again", push_identifier, tostring(push_errors[push_identifier])); |
| 218 end | 148 end |
| 219 end | 149 end |
| 220 end | 150 end |
| 221 return true; | 151 return true; |
| 254 node = push_node; | 184 node = push_node; |
| 255 include_payload = include_payload; | 185 include_payload = include_payload; |
| 256 options = publish_options and st.preserialize(publish_options); | 186 options = publish_options and st.preserialize(publish_options); |
| 257 timestamp = os_time(); | 187 timestamp = os_time(); |
| 258 }; | 188 }; |
| 259 local ok = push_store:set_identifier(origin.username, push_identifier, push_service); | 189 push_store:set_identifier(origin.username, push_identifier, push_service); |
| 190 local ok = push_store:flush_to_disk(origin.username); | |
| 260 if not ok then | 191 if not ok then |
| 261 origin.send(st.error_reply(stanza, "wait", "internal-server-error")); | 192 origin.send(st.error_reply(stanza, "wait", "internal-server-error")); |
| 262 else | 193 else |
| 263 origin.push_identifier = push_identifier; | 194 origin.push_identifier = push_identifier; |
| 264 origin.push_settings = push_service; | 195 origin.push_settings = push_service; |
| 288 origin.push_settings = nil; | 219 origin.push_settings = nil; |
| 289 origin.first_hibernated_push = nil; | 220 origin.first_hibernated_push = nil; |
| 290 end | 221 end |
| 291 user_push_services[key] = nil; | 222 user_push_services[key] = nil; |
| 292 push_errors[key] = nil; | 223 push_errors[key] = nil; |
| 293 if module.unhook then | 224 for stanza_id, identifier in pairs(id2identifier) do |
| 294 local stanza_id = hashes.sha256(key, true) | 225 if identifier == key then |
| 295 module:unhook("iq-error/host/"..stanza_id, handle_push_error); | 226 module:unhook("iq-error/host/"..stanza_id, handle_push_error); |
| 296 module:unhook("iq-result/host/"..stanza_id, handle_push_success); | 227 module:unhook("iq-result/host/"..stanza_id, handle_push_success); |
| 297 id2node[stanza_id] = nil; | 228 id2node[stanza_id] = nil; |
| 298 end | 229 id2identifier[stanza_id] = nil; |
| 299 end | 230 end |
| 300 end | 231 end |
| 301 local ok = push_store:set(origin.username, user_push_services); | 232 end |
| 233 end | |
| 234 local ok = push_store:flush_to_disk(origin.username); | |
| 302 if not ok then | 235 if not ok then |
| 303 origin.send(st.error_reply(stanza, "wait", "internal-server-error")); | 236 origin.send(st.error_reply(stanza, "wait", "internal-server-error")); |
| 304 else | 237 else |
| 305 origin.send(st.reply(stanza)); | 238 origin.send(st.reply(stanza)); |
| 306 end | 239 end |
| 307 return true; | 240 return true; |
| 308 end | 241 end |
| 309 module:hook("iq-set/self/"..xmlns_push..":disable", push_disable); | 242 module:hook("iq-set/self/"..xmlns_push..":disable", push_disable); |
| 310 | |
| 311 -- Patched version of util.stanza:find() that supports giving stanza names | |
| 312 -- without their namespace, allowing for every namespace. | |
| 313 local function find(self, path) | |
| 314 local pos = 1; | |
| 315 local len = #path + 1; | |
| 316 | |
| 317 repeat | |
| 318 local xmlns, name, text; | |
| 319 local char = s_sub(path, pos, pos); | |
| 320 if char == "@" then | |
| 321 return self.attr[s_sub(path, pos + 1)]; | |
| 322 elseif char == "{" then | |
| 323 xmlns, pos = s_match(path, "^([^}]+)}()", pos + 1); | |
| 324 end | |
| 325 name, text, pos = s_match(path, "^([^@/#]*)([/#]?)()", pos); | |
| 326 name = name ~= "" and name or nil; | |
| 327 if pos == len then | |
| 328 if text == "#" then | |
| 329 local child = xmlns ~= nil and self:get_child(name, xmlns) or self:child_with_name(name); | |
| 330 return child and child:get_text() or nil; | |
| 331 end | |
| 332 return xmlns ~= nil and self:get_child(name, xmlns) or self:child_with_name(name); | |
| 333 end | |
| 334 self = xmlns ~= nil and self:get_child(name, xmlns) or self:child_with_name(name); | |
| 335 until not self | |
| 336 return nil; | |
| 337 end | |
| 338 | 243 |
| 339 -- is this push a high priority one (this is needed for ios apps not using voip pushes) | 244 -- is this push a high priority one (this is needed for ios apps not using voip pushes) |
| 340 local function is_important(stanza) | 245 local function is_important(stanza) |
| 341 local st_name = stanza and stanza.name or nil; | 246 local st_name = stanza and stanza.name or nil; |
| 342 if not st_name then return false; end -- nonzas are never important here | 247 if not st_name then return false; end -- nonzas are never important here |
| 346 -- unpack carbon copies | 251 -- unpack carbon copies |
| 347 local stanza_direction = "in"; | 252 local stanza_direction = "in"; |
| 348 local carbon; | 253 local carbon; |
| 349 local st_type; | 254 local st_type; |
| 350 -- support carbon copied message stanzas having an arbitrary message-namespace or no message-namespace at all | 255 -- support carbon copied message stanzas having an arbitrary message-namespace or no message-namespace at all |
| 351 if not carbon then carbon = find(stanza, "{urn:xmpp:carbons:2}/forwarded/message"); end | 256 if not carbon then carbon = stanza:find("{urn:xmpp:carbons:2}/{urn:xmpp:forward:0}/{jabber:client}message"); end |
| 352 if not carbon then carbon = find(stanza, "{urn:xmpp:carbons:1}/forwarded/message"); end | |
| 353 stanza_direction = carbon and stanza:child_with_name("sent") and "out" or "in"; | 257 stanza_direction = carbon and stanza:child_with_name("sent") and "out" or "in"; |
| 354 if carbon then stanza = carbon; end | 258 if carbon then stanza = carbon; end |
| 355 st_type = stanza.attr.type; | 259 st_type = stanza.attr.type; |
| 356 | 260 |
| 357 -- headline message are always not important | 261 -- headline message are always not important |
| 388 }; | 292 }; |
| 389 | 293 |
| 390 -- http://xmpp.org/extensions/xep-0357.html#publishing | 294 -- http://xmpp.org/extensions/xep-0357.html#publishing |
| 391 local function handle_notify_request(stanza, node, user_push_services, log_push_decline) | 295 local function handle_notify_request(stanza, node, user_push_services, log_push_decline) |
| 392 local pushes = 0; | 296 local pushes = 0; |
| 393 if not user_push_services or next(user_push_services) == nil then return pushes end | 297 if not #user_push_services then return pushes end |
| 394 | 298 |
| 395 for push_identifier, push_info in pairs(user_push_services) do | 299 for push_identifier, push_info in pairs(user_push_services) do |
| 396 local send_push = true; -- only send push to this node when not already done for this stanza or if no stanza is given at all | 300 local send_push = true; -- only send push to this node when not already done for this stanza or if no stanza is given at all |
| 397 if stanza then | 301 if stanza then |
| 398 if not stanza._push_notify then stanza._push_notify = {}; end | 302 if not stanza._push_notify then stanza._push_notify = {}; end |
| 405 stanza._push_notify[push_identifier] = true; | 309 stanza._push_notify[push_identifier] = true; |
| 406 end | 310 end |
| 407 | 311 |
| 408 if send_push then | 312 if send_push then |
| 409 -- construct push stanza | 313 -- construct push stanza |
| 410 local stanza_id = hashes.sha256(push_identifier, true); | 314 local stanza_id = hashes.sha256(random.bytes(8), true); |
| 411 local push_publish = st.iq({ to = push_info.jid, from = module.host, type = "set", id = stanza_id }) | 315 local push_publish = st.iq({ to = push_info.jid, from = module.host, type = "set", id = stanza_id }) |
| 412 :tag("pubsub", { xmlns = "http://jabber.org/protocol/pubsub" }) | 316 :tag("pubsub", { xmlns = "http://jabber.org/protocol/pubsub" }) |
| 413 :tag("publish", { node = push_info.node }) | 317 :tag("publish", { node = push_info.node }) |
| 414 :tag("item") | 318 :tag("item") |
| 415 :tag("notification", { xmlns = xmlns_push }); | 319 :tag("notification", { xmlns = xmlns_push }); |
| 436 module:log("debug", "Sending%s push notification for %s@%s to %s (%s)", form_data["last-message-body"] and " important" or "", node, module.host, push_info.jid, tostring(push_info.node)); | 340 module:log("debug", "Sending%s push notification for %s@%s to %s (%s)", form_data["last-message-body"] and " important" or "", node, module.host, push_info.jid, tostring(push_info.node)); |
| 437 -- module:log("debug", "PUSH STANZA: %s", tostring(push_publish)); | 341 -- module:log("debug", "PUSH STANZA: %s", tostring(push_publish)); |
| 438 -- handle push errors for this node | 342 -- handle push errors for this node |
| 439 if push_errors[push_identifier] == nil then | 343 if push_errors[push_identifier] == nil then |
| 440 push_errors[push_identifier] = 0; | 344 push_errors[push_identifier] = 0; |
| 441 module:hook("iq-error/host/"..stanza_id, handle_push_error); | 345 end |
| 442 module:hook("iq-result/host/"..stanza_id, handle_push_success); | 346 module:hook("iq-error/host/"..stanza_id, handle_push_error); |
| 443 id2node[stanza_id] = node; | 347 module:hook("iq-result/host/"..stanza_id, handle_push_success); |
| 444 end | 348 id2node[stanza_id] = node; |
| 349 id2identifier[stanza_id] = push_identifier; | |
| 445 module:send(push_publish); | 350 module:send(push_publish); |
| 446 pushes = pushes + 1; | 351 pushes = pushes + 1; |
| 447 end | 352 end |
| 448 end | 353 end |
| 449 return pushes; | 354 return pushes; |
| 498 if not session.push_queue then session.push_queue = {}; end | 403 if not session.push_queue then session.push_queue = {}; end |
| 499 local queue = session.push_queue; | 404 local queue = session.push_queue; |
| 500 queue[#queue+1] = st.clone(stanza); | 405 queue[#queue+1] = st.clone(stanza); |
| 501 if #queue == 1 then -- first stanza --> start timer | 406 if #queue == 1 then -- first stanza --> start timer |
| 502 session.log("debug", "Invoking cloud handle_notify_request() for newly smacks queued stanza (in a moment)"); | 407 session.log("debug", "Invoking cloud handle_notify_request() for newly smacks queued stanza (in a moment)"); |
| 503 session.awaiting_push_timer = stoppable_timer(1e-06, function () | 408 session.awaiting_push_timer = module:add_timer(1e-06, function () |
| 504 session.log("debug", "Invoking cloud handle_notify_request() for newly smacks queued stanzas (now in timer)"); | 409 session.log("debug", "Invoking cloud handle_notify_request() for newly smacks queued stanzas (now in timer)"); |
| 505 process_stanza_queue(session.push_queue, session, "push"); | 410 process_stanza_queue(session.push_queue, session, "push"); |
| 506 session.push_queue = {}; -- clean up queue after push | 411 session.push_queue = {}; -- clean up queue after push |
| 507 end); | 412 end); |
| 508 end | 413 end |
| 550 to = to and jid.split(to) or event.origin.username; | 455 to = to and jid.split(to) or event.origin.username; |
| 551 | 456 |
| 552 -- only notify if the stanza destination is the mam user we store it for | 457 -- only notify if the stanza destination is the mam user we store it for |
| 553 if event.for_user == to then | 458 if event.for_user == to then |
| 554 local user_push_services = push_store:get(to); | 459 local user_push_services = push_store:get(to); |
| 555 if next(user_push_services) == nil then return end | |
| 556 | 460 |
| 557 -- only notify nodes with no active sessions (smacks is counted as active and handled separate) | 461 -- only notify nodes with no active sessions (smacks is counted as active and handled separate) |
| 558 local notify_push_services = {}; | 462 local notify_push_services = {}; |
| 559 for identifier, push_info in pairs(user_push_services) do | 463 for identifier, push_info in pairs(user_push_services) do |
| 560 local identifier_found = nil; | 464 local identifier_found = nil; |
| 582 module:hook("archive-message-added", archive_message_added); | 486 module:hook("archive-message-added", archive_message_added); |
| 583 | 487 |
| 584 local function send_ping(event) | 488 local function send_ping(event) |
| 585 local user = event.user; | 489 local user = event.user; |
| 586 local push_services = event.push_services or push_store:get(user); | 490 local push_services = event.push_services or push_store:get(user); |
| 587 handle_notify_request(nil, user, push_services, true); | 491 module:log("debug", "Handling event 'cloud-notify-ping' for user '%s'", user); |
| 492 local retval = handle_notify_request(nil, user, push_services, true); | |
| 493 module:log("debug", "handle_notify_request() returned %s", tostring(retval)); | |
| 588 end | 494 end |
| 589 -- can be used by other modules to ping one or more (or all) push endpoints | 495 -- can be used by other modules to ping one or more (or all) push endpoints |
| 590 module:hook("cloud-notify-ping", send_ping); | 496 module:hook("cloud-notify-ping", send_ping); |
| 591 | 497 |
| 592 module:log("info", "Module loaded"); | 498 module:log("info", "Module loaded"); |
| 593 function module.unload() | 499 function module.unload() |
| 594 if module.unhook then | |
| 595 module:unhook("account-disco-info", account_dico_info); | |
| 596 module:unhook("iq-set/self/"..xmlns_push..":enable", push_enable); | |
| 597 module:unhook("iq-set/self/"..xmlns_push..":disable", push_disable); | |
| 598 | |
| 599 module:unhook("smacks-hibernation-start", hibernate_session); | |
| 600 module:unhook("smacks-hibernation-end", restore_session); | |
| 601 module:unhook("smacks-ack-delayed", ack_delayed); | |
| 602 module:unhook("archive-message-added", archive_message_added); | |
| 603 module:unhook("cloud-notify-ping", send_ping); | |
| 604 | |
| 605 for push_identifier, _ in pairs(push_errors) do | |
| 606 local stanza_id = hashes.sha256(push_identifier, true); | |
| 607 module:unhook("iq-error/host/"..stanza_id, handle_push_error); | |
| 608 module:unhook("iq-result/host/"..stanza_id, handle_push_success); | |
| 609 id2node[stanza_id] = nil; | |
| 610 end | |
| 611 end | |
| 612 | |
| 613 module:log("info", "Module unloaded"); | 500 module:log("info", "Module unloaded"); |
| 614 end | 501 end |
