comparison mod_cloud_notify/mod_cloud_notify.lua @ 3055:6abee021d9db

mod_cloud_notify: Limit number of devices to 5 and change some default settings
author tmolitor <thilo@eightysoft.de>
date Mon, 28 May 2018 05:28:07 +0200
parents 7ee59f417c16
children 6b860de18a53
comparison
equal deleted inserted replaced
3054:5e94061c1aa7 3055:6abee021d9db
1 -- XEP-0357: Push (aka: My mobile OS vendor won't let me have persistent TCP connections) 1 -- XEP-0357: Push (aka: My mobile OS vendor won't let me have persistent TCP connections)
2 -- Copyright (C) 2015-2016 Kim Alvefur 2 -- Copyright (C) 2015-2016 Kim Alvefur
3 -- Copyright (C) 2017 Thilo Molitor 3 -- Copyright (C) 2017-2018 Thilo Molitor
4 -- 4 --
5 -- This file is MIT/X11 licensed. 5 -- This file is MIT/X11 licensed.
6 6
7 local t_insert = table.insert; 7 local t_insert = table.insert;
8 local s_match = string.match; 8 local s_match = string.match;
9 local s_sub = string.sub; 9 local s_sub = string.sub;
10 local os_time = os.time;
10 local st = require"util.stanza"; 11 local st = require"util.stanza";
11 local jid = require"util.jid"; 12 local jid = require"util.jid";
12 local dataform = require"util.dataforms".new; 13 local dataform = require"util.dataforms".new;
13 local filters = require"util.filters"; 14 local filters = require"util.filters";
14 local hashes = require"util.hashes"; 15 local hashes = require"util.hashes";
16 local xmlns_push = "urn:xmpp:push:0"; 17 local xmlns_push = "urn:xmpp:push:0";
17 18
18 -- configuration 19 -- configuration
19 local include_body = module:get_option_boolean("push_notification_with_body", false); 20 local include_body = module:get_option_boolean("push_notification_with_body", false);
20 local include_sender = module:get_option_boolean("push_notification_with_sender", false); 21 local include_sender = module:get_option_boolean("push_notification_with_sender", false);
21 local max_push_errors = module:get_option_number("push_max_errors", 50); 22 local max_push_errors = module:get_option_number("push_max_errors", 16);
22 local dummy_body = module:get_option_string("push_notification_important_body", ""); 23 local max_push_devices = module:get_option_number("push_max_devices", 5);
24 local dummy_body = module:get_option_string("push_notification_important_body", "New Message!");
23 25
24 local host_sessions = prosody.hosts[module.host].sessions; 26 local host_sessions = prosody.hosts[module.host].sessions;
25 local push_errors = {}; 27 local push_errors = {};
26 local id2node = {}; 28 local id2node = {};
29
30 -- ordered table iterator, allow to iterate on the natural order of the keys of a table,
31 -- see http://lua-users.org/wiki/SortedIteration
32 local function __genOrderedIndex( t )
33 local orderedIndex = {}
34 for key in pairs(t) do
35 table.insert( orderedIndex, key )
36 end
37 -- sort in reverse order (newest one first)
38 table.sort( orderedIndex, function(a, b)
39 if a == nil or t[a] == nil or b == nil or t[b] == nil then return false end
40 -- only one timestamp given, this is the newer one
41 if t[a].timestamp ~= nil and t[b].timestamp == nil then return true end
42 if t[a].timestamp == nil and t[b].timestamp ~= nil then return false end
43 -- both timestamps given, sort normally
44 if t[a].timestamp ~= nil and t[b].timestamp ~= nil then return t[a].timestamp > t[b].timestamp end
45 return false -- normally not reached
46 end)
47 return orderedIndex
48 end
49 local function orderedNext(t, state)
50 -- Equivalent of the next function, but returns the keys in timestamp
51 -- order. We use a temporary ordered key table that is stored in the
52 -- table being iterated.
53
54 local key = nil
55 --print("orderedNext: state = "..tostring(state) )
56 if state == nil then
57 -- the first time, generate the index
58 t.__orderedIndex = __genOrderedIndex( t )
59 key = t.__orderedIndex[1]
60 else
61 -- fetch the next value
62 for i = 1,table.getn(t.__orderedIndex) do
63 if t.__orderedIndex[i] == state then
64 key = t.__orderedIndex[i+1]
65 end
66 end
67 end
68
69 if key then
70 return key, t[key]
71 end
72
73 -- no more value to return, cleanup
74 t.__orderedIndex = nil
75 return
76 end
77 local function orderedPairs(t)
78 -- Equivalent of the pairs() function on tables. Allows to iterate
79 -- in order
80 return orderedNext, t, nil
81 end
82
83 -- small helper function to return new table with only "maximum" elements containing only the newest entries
84 local function reduce_table(table, maximum)
85 local count = 0;
86 local result = {};
87 for key, value in orderedPairs(table) do
88 count = count + 1;
89 if count > maximum then break end
90 result[key] = value;
91 end
92 return result;
93 end
27 94
28 -- For keeping state across reloads while caching reads 95 -- For keeping state across reloads while caching reads
29 local push_store = (function() 96 local push_store = (function()
30 local store = module:open_store(); 97 local store = module:open_store();
31 local push_services = {}; 98 local push_services = {};
42 end 109 end
43 if not push_services[user] then push_services[user] = {} end 110 if not push_services[user] then push_services[user] = {} end
44 return push_services[user], true; 111 return push_services[user], true;
45 end 112 end
46 function api:set(user, data) 113 function api:set(user, data)
47 push_services[user] = data; 114 push_services[user] = reduce_table(data, max_push_devices);
48 local ok, err = store:set(user, push_services[user]); 115 local ok, err = store:set(user, push_services[user]);
49 if not ok then 116 if not ok then
50 module:log("error", "Error writing push notification storage for user '%s': %s", user, tostring(err)); 117 module:log("error", "Error writing push notification storage for user '%s': %s", user, tostring(err));
51 return false; 118 return false;
52 end 119 end
158 local push_service = { 225 local push_service = {
159 jid = push_jid; 226 jid = push_jid;
160 node = push_node; 227 node = push_node;
161 include_payload = include_payload; 228 include_payload = include_payload;
162 options = publish_options and st.preserialize(publish_options); 229 options = publish_options and st.preserialize(publish_options);
230 timestamp = os_time();
163 }; 231 };
164 local ok = push_store:set_identifier(origin.username, push_identifier, push_service); 232 local ok = push_store:set_identifier(origin.username, push_identifier, push_service);
165 if not ok then 233 if not ok then
166 origin.send(st.error_reply(stanza, "wait", "internal-server-error")); 234 origin.send(st.error_reply(stanza, "wait", "internal-server-error"));
167 else 235 else
416 end 484 end
417 485
418 -- archive message added 486 -- archive message added
419 local function archive_message_added(event) 487 local function archive_message_added(event)
420 -- event is: { origin = origin, stanza = stanza, for_user = store_user, id = id } 488 -- event is: { origin = origin, stanza = stanza, for_user = store_user, id = id }
421 -- only notify for new mam messages when at least one device is only 489 -- only notify for new mam messages when at least one device is online
422 if not event.for_user or not host_sessions[event.for_user] then return; end 490 if not event.for_user or not host_sessions[event.for_user] then return; end
423 local stanza = event.stanza; 491 local stanza = event.stanza;
424 local user_session = host_sessions[event.for_user].sessions; 492 local user_session = host_sessions[event.for_user].sessions;
425 local to = stanza.attr.to; 493 local to = stanza.attr.to;
426 to = to and jid.split(to) or event.origin.username; 494 to = to and jid.split(to) or event.origin.username;