Mercurial > prosody-modules
changeset 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 (2018-05-28) |
parents | 5e94061c1aa7 |
children | 6fce9a935b38 |
files | mod_cloud_notify/README.markdown mod_cloud_notify/mod_cloud_notify.lua |
diffstat | 2 files changed, 80 insertions(+), 11 deletions(-) [+] |
line wrap: on
line diff
--- a/mod_cloud_notify/README.markdown Mon May 28 05:27:03 2018 +0200 +++ b/mod_cloud_notify/README.markdown Mon May 28 05:28:07 2018 +0200 @@ -46,12 +46,13 @@ Configuration ============= - Option Default Description - ------------------------------------ --------- --------------------------------------------------------------------------------------------------------------- - `push_notification_with_body` `false` Whether or not to send the message body to remote pubsub node. - `push_notification_with_sender` `false` Whether or not to send the message sender to remote pubsub node. - `push_max_errors` `50` How much persistent push errors are tolerated before notifications for the identifier in question are disabled - `push_notification_important_body` `` The body text to use when the stanza is important (see above), no message body is sent if this is empty + Option Default Description + ------------------------------------ ----------------- ------------------------------------------------------------------------------------------------------------------- + `push_notification_with_body` `false` Whether or not to send the message body to remote pubsub node. + `push_notification_with_sender` `false` Whether or not to send the message sender to remote pubsub node. + `push_max_errors` `16` How much persistent push errors are tolerated before notifications for the identifier in question are disabled + `push_notification_important_body` `New Message!` The body text to use when the stanza is important (see above), no message body is sent if this is empty + `push_max_devices` `5` The number of allowed devices per user (the oldest devices are automatically removed if this threshold is reached) There are privacy implications for enabling these options because plaintext content and metadata will be shared with centralized servers
--- a/mod_cloud_notify/mod_cloud_notify.lua Mon May 28 05:27:03 2018 +0200 +++ b/mod_cloud_notify/mod_cloud_notify.lua Mon May 28 05:28:07 2018 +0200 @@ -1,12 +1,13 @@ -- XEP-0357: Push (aka: My mobile OS vendor won't let me have persistent TCP connections) -- Copyright (C) 2015-2016 Kim Alvefur --- Copyright (C) 2017 Thilo Molitor +-- Copyright (C) 2017-2018 Thilo Molitor -- -- This file is MIT/X11 licensed. local t_insert = table.insert; local s_match = string.match; local s_sub = string.sub; +local os_time = os.time; local st = require"util.stanza"; local jid = require"util.jid"; local dataform = require"util.dataforms".new; @@ -18,13 +19,79 @@ -- configuration local include_body = module:get_option_boolean("push_notification_with_body", false); local include_sender = module:get_option_boolean("push_notification_with_sender", false); -local max_push_errors = module:get_option_number("push_max_errors", 50); -local dummy_body = module:get_option_string("push_notification_important_body", ""); +local max_push_errors = module:get_option_number("push_max_errors", 16); +local max_push_devices = module:get_option_number("push_max_devices", 5); +local dummy_body = module:get_option_string("push_notification_important_body", "New Message!"); local host_sessions = prosody.hosts[module.host].sessions; local push_errors = {}; local id2node = {}; +-- ordered table iterator, allow to iterate on the natural order of the keys of a table, +-- see http://lua-users.org/wiki/SortedIteration +local function __genOrderedIndex( t ) + local orderedIndex = {} + for key in pairs(t) do + table.insert( orderedIndex, key ) + end + -- sort in reverse order (newest one first) + table.sort( orderedIndex, function(a, b) + if a == nil or t[a] == nil or b == nil or t[b] == nil then return false end + -- only one timestamp given, this is the newer one + if t[a].timestamp ~= nil and t[b].timestamp == nil then return true end + if t[a].timestamp == nil and t[b].timestamp ~= nil then return false end + -- both timestamps given, sort normally + if t[a].timestamp ~= nil and t[b].timestamp ~= nil then return t[a].timestamp > t[b].timestamp end + return false -- normally not reached + end) + return orderedIndex +end +local function orderedNext(t, state) + -- Equivalent of the next function, but returns the keys in timestamp + -- order. We use a temporary ordered key table that is stored in the + -- table being iterated. + + local key = nil + --print("orderedNext: state = "..tostring(state) ) + if state == nil then + -- the first time, generate the index + t.__orderedIndex = __genOrderedIndex( t ) + key = t.__orderedIndex[1] + else + -- fetch the next value + for i = 1,table.getn(t.__orderedIndex) do + if t.__orderedIndex[i] == state then + key = t.__orderedIndex[i+1] + end + end + end + + if key then + return key, t[key] + end + + -- no more value to return, cleanup + t.__orderedIndex = nil + return +end +local function orderedPairs(t) + -- Equivalent of the pairs() function on tables. Allows to iterate + -- in order + return orderedNext, t, nil +end + +-- small helper function to return new table with only "maximum" elements containing only the newest entries +local function reduce_table(table, maximum) + local count = 0; + local result = {}; + for key, value in orderedPairs(table) do + count = count + 1; + if count > maximum then break end + result[key] = value; + end + return result; +end + -- For keeping state across reloads while caching reads local push_store = (function() local store = module:open_store(); @@ -44,7 +111,7 @@ return push_services[user], true; end function api:set(user, data) - push_services[user] = data; + push_services[user] = reduce_table(data, max_push_devices); local ok, err = store:set(user, push_services[user]); if not ok then module:log("error", "Error writing push notification storage for user '%s': %s", user, tostring(err)); @@ -160,6 +227,7 @@ node = push_node; include_payload = include_payload; options = publish_options and st.preserialize(publish_options); + timestamp = os_time(); }; local ok = push_store:set_identifier(origin.username, push_identifier, push_service); if not ok then @@ -418,7 +486,7 @@ -- archive message added local function archive_message_added(event) -- event is: { origin = origin, stanza = stanza, for_user = store_user, id = id } - -- only notify for new mam messages when at least one device is only + -- only notify for new mam messages when at least one device is online if not event.for_user or not host_sessions[event.for_user] then return; end local stanza = event.stanza; local user_session = host_sessions[event.for_user].sessions;