Mercurial > prosody-modules
comparison mod_cloud_notify/mod_cloud_notify.lua @ 2712:d89ab70808f6
mod_cloud_notify: fix bug when multiple resources are used
This bug was triggered under the rare circumstances that a message arrived
and one resource was smacks hibernated while the other one(s) were offline.
Then only the hibernated resource but not the offline one(s) (or the other
way round) got notified.
author | tmolitor <thilo@eightysoft.de> |
---|---|
date | Mon, 08 May 2017 18:24:29 +0200 |
parents | 6e01878103c0 |
children | 75b137cf869a |
comparison
equal
deleted
inserted
replaced
2711:ff1f7e61517f | 2712:d89ab70808f6 |
---|---|
205 { name = "last-message-body"; type = "text-single"; }; | 205 { name = "last-message-body"; type = "text-single"; }; |
206 }; | 206 }; |
207 | 207 |
208 -- http://xmpp.org/extensions/xep-0357.html#publishing | 208 -- http://xmpp.org/extensions/xep-0357.html#publishing |
209 local function handle_notify_request(stanza, node, user_push_services) | 209 local function handle_notify_request(stanza, node, user_push_services) |
210 if not user_push_services or not #user_push_services then return end | 210 local pushes = 0; |
211 if not user_push_services or not #user_push_services then return pushes end | |
211 | 212 |
212 for push_identifier, push_info in pairs(user_push_services) do | 213 for push_identifier, push_info in pairs(user_push_services) do |
214 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 | |
213 if stanza then | 215 if stanza then |
214 if not stanza._push_notify then stanza._push_notify = {}; end | 216 if not stanza._push_notify then stanza._push_notify = {}; end |
215 if stanza._push_notify[push_identifier] then | 217 if stanza._push_notify[push_identifier] then |
216 module:log("debug", "Already sent push notification for %s@%s to %s (%s)", node, module.host, push_info.jid, tostring(push_info.node)); | 218 module:log("debug", "Already sent push notification for %s@%s to %s (%s)", node, module.host, push_info.jid, tostring(push_info.node)); |
217 return; | 219 send_push = false; |
218 end | 220 end |
219 stanza._push_notify[push_identifier] = true; | 221 stanza._push_notify[push_identifier] = true; |
220 end | 222 end |
221 | 223 |
222 -- increment count and save it | 224 if send_push then |
223 push_info.count = push_info.count + 1; | 225 -- increment count and save it |
224 push_store:set_identifier(node, push_identifier, push_info); | 226 push_info.count = push_info.count + 1; |
225 -- construct push stanza | 227 push_store:set_identifier(node, push_identifier, push_info); |
226 local stanza_id = hashes.sha256(push_identifier, true); | 228 -- construct push stanza |
227 local push_publish = st.iq({ to = push_info.jid, from = node .. "@" .. module.host, type = "set", id = stanza_id }) | 229 local stanza_id = hashes.sha256(push_identifier, true); |
228 :tag("pubsub", { xmlns = "http://jabber.org/protocol/pubsub" }) | 230 local push_publish = st.iq({ to = push_info.jid, from = node .. "@" .. module.host, type = "set", id = stanza_id }) |
229 :tag("publish", { node = push_info.node }) | 231 :tag("pubsub", { xmlns = "http://jabber.org/protocol/pubsub" }) |
230 :tag("item") | 232 :tag("publish", { node = push_info.node }) |
231 :tag("notification", { xmlns = xmlns_push }); | 233 :tag("item") |
232 local form_data = { | 234 :tag("notification", { xmlns = xmlns_push }); |
233 ["message-count"] = tostring(push_info.count); | 235 local form_data = { |
234 }; | 236 ["message-count"] = tostring(push_info.count); |
235 if stanza and include_sender then | 237 }; |
236 form_data["last-message-sender"] = stanza.attr.from; | 238 if stanza and include_sender then |
237 end | 239 form_data["last-message-sender"] = stanza.attr.from; |
238 if stanza and include_body then | 240 end |
239 form_data["last-message-body"] = stanza:get_child_text("body"); | 241 if stanza and include_body then |
240 end | 242 form_data["last-message-body"] = stanza:get_child_text("body"); |
241 push_publish:add_child(push_form:form(form_data)); | 243 end |
242 push_publish:up(); -- / notification | 244 push_publish:add_child(push_form:form(form_data)); |
243 push_publish:up(); -- / publish | 245 push_publish:up(); -- / notification |
244 push_publish:up(); -- / pubsub | 246 push_publish:up(); -- / publish |
245 if push_info.options then | 247 push_publish:up(); -- / pubsub |
246 push_publish:tag("publish-options"):add_child(st.deserialize(push_info.options)); | 248 if push_info.options then |
247 end | 249 push_publish:tag("publish-options"):add_child(st.deserialize(push_info.options)); |
248 -- send out push | 250 end |
249 module:log("debug", "Sending push notification for %s@%s to %s (%s)", node, module.host, push_info.jid, tostring(push_info.node)); | 251 -- send out push |
250 -- handle push errors for this node | 252 module:log("debug", "Sending push notification for %s@%s to %s (%s)", node, module.host, push_info.jid, tostring(push_info.node)); |
251 if push_errors[push_identifier] == nil then | 253 -- handle push errors for this node |
252 push_errors[push_identifier] = 0; | 254 if push_errors[push_identifier] == nil then |
253 module:hook("iq-error/bare/"..stanza_id, handle_push_error); | 255 push_errors[push_identifier] = 0; |
254 module:hook("iq-result/bare/"..stanza_id, handle_push_success); | 256 module:hook("iq-error/bare/"..stanza_id, handle_push_error); |
255 end | 257 module:hook("iq-result/bare/"..stanza_id, handle_push_success); |
256 module:send(push_publish); | 258 end |
257 end | 259 module:send(push_publish); |
260 pushes = pushes + 1; | |
261 end | |
262 end | |
263 return pushes; | |
258 end | 264 end |
259 | 265 |
260 -- small helper function to extract relevant push settings | 266 -- small helper function to extract relevant push settings |
261 local function get_push_settings(stanza, session) | 267 local function get_push_settings(stanza, session) |
262 local to = stanza.attr.to; | 268 local to = stanza.attr.to; |
266 end | 272 end |
267 | 273 |
268 -- publish on offline message | 274 -- publish on offline message |
269 module:hook("message/offline/handle", function(event) | 275 module:hook("message/offline/handle", function(event) |
270 local node, user_push_services = get_push_settings(event.stanza, event.origin); | 276 local node, user_push_services = get_push_settings(event.stanza, event.origin); |
271 return handle_notify_request(event.stanza, node, user_push_services); | 277 handle_notify_request(event.stanza, node, user_push_services); |
272 end, 1); | 278 end, 1); |
273 | 279 |
274 -- publish on unacked smacks message | 280 -- publish on unacked smacks message |
275 local function process_smacks_stanza(stanza, session) | 281 local function process_smacks_stanza(stanza, session) |
276 if session.push_identifier then | 282 if session.push_identifier then |
348 else | 354 else |
349 notify_push_sevices[identifier] = push_info; | 355 notify_push_sevices[identifier] = push_info; |
350 end | 356 end |
351 end | 357 end |
352 | 358 |
353 return handle_notify_request(event.stanza, to, notify_push_sevices); | 359 handle_notify_request(event.stanza, to, notify_push_sevices); |
354 end | 360 end |
355 end | 361 end |
356 | 362 |
357 module:hook("smacks-hibernation-start", hibernate_session); | 363 module:hook("smacks-hibernation-start", hibernate_session); |
358 module:hook("smacks-hibernation-end", restore_session); | 364 module:hook("smacks-hibernation-end", restore_session); |
361 | 367 |
362 local function send_ping(event) | 368 local function send_ping(event) |
363 local user = event.user; | 369 local user = event.user; |
364 local user_push_services = push_store:get(user); | 370 local user_push_services = push_store:get(user); |
365 local push_services = event.push_services or user_push_services; | 371 local push_services = event.push_services or user_push_services; |
366 return handle_notify_request(nil, user, push_services); | 372 handle_notify_request(nil, user, push_services); |
367 end | 373 end |
368 -- can be used by other modules to ping one or more (or all) push endpoints | 374 -- can be used by other modules to ping one or more (or all) push endpoints |
369 module:hook("cloud-notify-ping", send_ping); | 375 module:hook("cloud-notify-ping", send_ping); |
370 | 376 |
371 -- TODO: this has to be done on first connect not on offline broadcast, else the counter will be incorrect | 377 -- TODO: this has to be done on first connect not on offline broadcast, else the counter will be incorrect |