local cache = require "util.cache"; local jid = require "util.jid"; local st = require "util.stanza"; local max_subscribers = module:get_option_number("muc_rai_max_subscribers", 1024); local muc_affiliation_store = module:open_store("config", "map"); local muc_archive = module:open_store("muc_log", "archive"); local xmlns_rai = "xmpp:prosody.im/protocol/rai"; local muc_markers = module:depends("muc_markers"); -- subscriber_jid -> { [room_jid] = interested } local subscribed_users = cache.new(max_subscribers, false); -- room_jid -> { [user_jid] = interested } local interested_users = {}; -- room_jid -> last_id local room_activity_cache = cache.new(1024); -- Send a single notification for a room, updating data structures as needed local function send_single_notification(user_jid, room_jid) local notification = st.message({ to = user_jid, from = module.host }) :tag("rai", { xmlns = xmlns_rai }) :text_tag("activity", room_jid) :up(); local interested_room_users = interested_users[room_jid]; if interested_room_users then interested_room_users[user_jid] = nil; end local interested_rooms = subscribed_users:get(user_jid); if interested_rooms then interested_rooms[room_jid] = nil; end module:log("debug", "Sending notification from %s to %s", room_jid, user_jid); return module:send(notification); end local function subscribe_room(user_jid, room_jid) local interested_rooms = subscribed_users:get(user_jid); if not interested_rooms then return nil, "not-subscribed"; end module:log("debug", "Subscribed %s to %s", user_jid, room_jid); interested_rooms[room_jid] = true; local interested_room_users = interested_users[room_jid]; if not interested_room_users then interested_room_users = {}; interested_users[room_jid] = interested_room_users; end interested_room_users[user_jid] = true; return true; end local function unsubscribe_room(user_jid, room_jid) local interested_rooms = subscribed_users:get(user_jid); if not interested_rooms then return nil, "not-subscribed"; end interested_rooms[room_jid] = nil; local interested_room_users = interested_users[room_jid]; if not interested_room_users then return true; end interested_room_users[user_jid] = nil; return true; end local function notify_interested_users(room_jid) module:log("warn", "NOTIFYING FOR %s", room_jid) local interested_room_users = interested_users[room_jid]; if not interested_room_users then module:log("debug", "Nobody interested in %s", room_jid); return; end for user_jid in pairs(interested_room_users) do send_single_notification(user_jid, room_jid); end return true; end local function unsubscribe_user_from_all_rooms(user_jid) local interested_rooms = subscribed_users:get(user_jid); if not interested_rooms then return nil, "not-subscribed"; end for room_jid in pairs(interested_rooms) do unsubscribe_room(user_jid, room_jid); end return true; end local function get_last_room_message_id(room_jid) local last_room_message_id = room_activity_cache:get(room_jid); if last_room_message_id then return last_room_message_id; end -- Load all the data! local query = { limit = 1; reverse = true; with = "message