jiti-meet/resources/prosody-plugins/mod_fmuc.lua

133 lines
4.6 KiB
Lua

--- activate under main muc component
--- Add the following config under the main muc component
--- muc_room_default_presence_broadcast = {
--- visitor = false;
--- participant = true;
--- moderator = true;
--- };
--- Enable in global modules: 's2s_bidi'
--- Make sure 's2s' is not in modules_disabled
local jid = require 'util.jid';
local st = require 'util.stanza';
local muc_domain_prefix = module:get_option_string('muc_mapper_domain_prefix', 'conference');
local main_domain = string.gsub(module.host, muc_domain_prefix..'.', '');
local function get_focus_occupant(room)
local focus_occupant = room._data.focus_occupant;
if focus_occupant then
return focus_occupant;
end
for _, n_occupant in room:each_occupant() do
if jid.node(n_occupant.jid) == 'focus' then
room._data.focus_occupant = n_occupant;
return n_occupant;
end
end
return nil;
end
-- mark all occupants as visitors
module:hook('muc-occupant-pre-join', function (event)
local occupant = event.occupant;
if jid.host(occupant.bare_jid) == main_domain then
occupant.role = 'visitor';
end
end, 3);
-- when occupant is leaving forward presences to jicofo for visitors
-- do not check occupant.role as it maybe already reset
-- if there are no main occupants or no visitors, destroy the room (give 15 seconds of grace period for reconnections)
module:hook('muc-occupant-left', function (event)
local room, occupant = event.room, event.occupant;
local occupant_domain = jid.host(occupant.bare_jid);
if occupant_domain == main_domain then
local focus_occupant = get_focus_occupant(room);
if not focus_occupant then
module:log('warn', 'No focus found for %s', room.jid);
return;
end
-- Let's forward unavailable presence to the special jicofo
local pr = st.presence({ to = focus_occupant.jid, from = occupant.nick, type = 'unavailable' })
:tag('x', { xmlns = 'http://jabber.org/protocol/muc#user' })
:tag('item', {
affiliation = room:get_affiliation(occupant.bare_jid) or 'none';
role = 'none';
nick = event.nick;
jid = occupant.bare_jid }):up()
:up();
room:route_stanza(pr);
end
if not room.destroying then
if room.xxl_destroy_timer then
room.xxl_destroy_timer:stop();
end
room.xxl_destroy_timer = module:add_timer(15, function()
-- let's check are all visitors in the room, if all a visitors - destroy it
-- if all are main-participants also destroy it
local main_count = 0;
local visitors_count = 0;
for _, o in room:each_occupant() do
-- if there are visitor and main participant there is no point continue
if main_count > 0 and visitors_count > 0 then
return;
end
if o.role == 'visitor' then
visitors_count = visitors_count + 1;
else
main_count = main_count + 1;
end
end
if main_count == 0 then
module:log('info', 'Will destroy:%s main_occupants:%s visitors:%s', room.jid, main_count, visitors_count);
room:destroy(nil, 'No main participants.');
elseif visitors_count == 0 then
module:log('info', 'Will destroy:%s main_occupants:%s visitors:%s', room.jid, main_count, visitors_count);
room:destroy(nil, 'No visitors.');
end
end);
end
end);
-- forward visitor presences to jicofo
module:hook('muc-broadcast-presence', function (event)
local occupant = event.occupant;
---- we are interested only of visitors presence to send it to jicofo
if occupant.role ~= 'visitor' then
return;
end
local room = event.room;
local focus_occupant = get_focus_occupant(room);
if not focus_occupant then
return;
end
local actor, base_presence, nick, reason, x = event.actor, event.stanza, event.nick, event.reason, event.x;
local actor_nick;
if actor then
actor_nick = jid.resource(room:get_occupant_jid(actor));
end
-- create a presence to send it to jicofo, as jicofo is special :)
local full_x = st.clone(x.full or x);
room:build_item_list(occupant, full_x, false, nick, actor_nick, actor, reason);
local full_p = st.clone(base_presence):add_child(full_x);
full_p.attr.to = focus_occupant.jid;
room:route_to_occupant(focus_occupant, full_p);
return;
end);