Software /
code /
prosody-modules
File
mod_groups_internal/mod_groups_internal.lua @ 4386:6357ac65b4eb
mod_groups_internal: allow delay of roster sync on group change
This is useful when executing a bulk change (e.g. a creation of
a group with many members) to avoid O(n^3).
author | Jonas Schäfer <jonas@wielicki.name> |
---|---|
date | Mon, 25 Jan 2021 21:33:38 +0100 |
parent | 4385:dfb34cc97028 |
child | 4388:7de3c955cfe2 |
line wrap: on
line source
local rostermanager = require"core.rostermanager"; local id = require "util.id"; local jid = require "util.jid"; local jid_join = jid.join; local host = module.host; local group_info_store = module:open_store("group_info"); local group_members_store = module:open_store("groups"); local group_memberships = module:open_store("groups", "map"); local is_contact_subscribed = rostermanager.is_contact_subscribed; -- Make a *one-way* subscription. User will see when contact is online, -- contact will not see when user is online. local function subscribe(user, user_jid, contact, contact_jid) -- Update user's roster to say subscription request is pending... rostermanager.set_contact_pending_out(user, host, contact_jid); -- Update contact's roster to say subscription request is pending... rostermanager.set_contact_pending_in(contact, host, user_jid); -- Update contact's roster to say subscription request approved... rostermanager.subscribed(contact, host, user_jid); -- Update user's roster to say subscription request approved... rostermanager.process_inbound_subscription_approval(user, host, contact_jid); -- Push updates to both rosters rostermanager.roster_push(user, host, contact_jid); rostermanager.roster_push(contact, host, user_jid); end local function user_groups(username) return pairs(group_memberships:get_all(username) or {}); end local function do_single_group_subscriptions(username, group_id) local members = group_members_store:get(group_id); if not members then return; end local user_jid = jid_join(username, host); for membername in pairs(members) do if membername ~= username then local member_jid = jid_join(membername, host); if not is_contact_subscribed(username, host, member_jid) then module:log("debug", "[group %s] Subscribing %s to %s", member_jid, user_jid); subscribe(membername, member_jid, username, user_jid); end if not is_contact_subscribed(membername, host, user_jid) then module:log("debug", "[group %s] Subscribing %s to %s", user_jid, member_jid); subscribe(username, user_jid, membername, member_jid); end end end end local function do_all_group_subscriptions_by_user(username) for group_id in user_groups(username) do do_single_group_subscriptions(username, group_id); end end local function do_all_group_subscriptions_by_group(group_id) for membername in pairs(get_members(group_id)) do do_single_group_subscriptions(membername, group_id); end end module:hook("resource-bind", function(event) module:log("debug", "Updating group subscriptions..."); do_all_group_subscriptions_by_user(event.session.username); end); local function get_group_muc(group_id) -- Group MUC local group_info = group_info_store:get(group_id); if group_info and group_info.muc_jid then local muc_jid = group_info.muc_jid; local mod_muc = hosts[jid.host(muc_jid)].modules.muc; if mod_muc then local room = mod_muc.get_room_from_jid(muc_jid); if not room then room = mod_muc.create_room(muc_jid); end return room; end end end --luacheck: ignore 131 function create(group_info, create_muc, group_id) if not group_info.name then return nil, "group-name-required"; end if group_id then if exists(group_id) then return nil, "conflict" end else group_id = id.short(); end if create_muc then return nil, "not-implemented"; end local ok = group_info_store:set(group_id, { name = group_info.name; }); if not ok then return nil, "internal-server-error"; end return group_id; end function get_info(group_id) return group_info_store:get(group_id); end function set_info(group_id, info) if not info then return nil, "bad-request" end if not info.name or #info.name == 0 then return nil, "bad-request" end local ok = group_info_store:set(group_id, info); if not ok then return nil, "internal-server-error"; end return true end function get_members(group_id) return group_members_store:get(group_id); end function exists(group_id) return not not get_info(group_id); end function get_user_groups(username) local groups = {}; do local group_set = group_memberships:get_all(username); if group_set then for group_id in pairs(group_set) do table.insert(groups, group_id); end end end return groups; end function delete(group_id) if group_members_store:set(group_id, nil) then return group_info_store:set(group_id, nil); end return nil, "internal-server-error"; end function add_member(group_id, username, delay_update) local group_info = group_info_store:get(group_id); if not group_info then return nil, "group-not-found"; end if not group_memberships:set(group_id, username, {}) then return nil, "internal-server-error"; end if not delay_update then do_all_group_subscriptions_by_group(group_id); end return true; end function remove_member(group_id, username) local group_info = group_info_store:get(group_id); if not group_info then return nil, "group-not-found"; end if not group_memberships:set(group_id, username, nil) then return nil, "internal-server-error"; end return true; end function sync(group_id) do_all_group_subscriptions_by_group(group_id) end -- Returns iterator over group ids function groups() return group_info_store:users(); end