117 lines
4.4 KiB
Lua
117 lines
4.4 KiB
Lua
--- activate under the main muc component
|
|
|
|
local MIN = module:get_option_number("conference_max_minutes", 5)
|
|
local TIMEOUT = MIN * 60
|
|
|
|
-- Gratis time granted past the limit so people can say their goodbyes and
|
|
-- leave on their own instead of being cut off mid-sentence. Clients still see
|
|
-- their countdown end at TIMEOUT - they spend the grace period in the visible
|
|
-- over-schedule state, which is the cue to wrap up - the room is simply not
|
|
-- torn down until it elapses. 0 (the default) destroys the room the moment the
|
|
-- limit is reached.
|
|
local GRACE = module:get_option_number("conference_grace_seconds", 0)
|
|
local DESTROY_AT = TIMEOUT + GRACE
|
|
|
|
local is_healthcheck_room = module:require "util".is_healthcheck_room
|
|
local st = require "util.stanza"
|
|
local json = require "cjson.safe"
|
|
local array = require "util.array";
|
|
module:log('info', "loaded")
|
|
|
|
local restricted_rooms = array{};
|
|
|
|
-- The `type` the time-timer feature in jitsi-meet matches on. Sent as a
|
|
-- json-message from the room JID so lib-jitsi-meet surfaces it as a
|
|
-- NON_PARTICIPANT_MESSAGE_RECEIVED (a server-originated, non-participant
|
|
-- message) rather than a participant endpoint message.
|
|
local TIME_RESTRICTED_MESSAGE_TYPE = 'time_restricted';
|
|
|
|
-- Sends the time-timer json-message to a single occupant. `durationSeconds` is
|
|
-- the full meeting length and `elapsedSeconds` how far in we are, so every
|
|
-- client - first joiner or last - lands on the same countdown.
|
|
local function send_time_timer(room, to_jid)
|
|
local elapsed = os.time() - (room.time_restricted_created or os.time());
|
|
local body, error = json.encode({
|
|
type = TIME_RESTRICTED_MESSAGE_TYPE;
|
|
durationSeconds = TIMEOUT;
|
|
elapsedSeconds = elapsed;
|
|
});
|
|
|
|
if not body then
|
|
module:log('error', 'failed to encode time-timer message room:%s error:%s', room.jid, error);
|
|
return;
|
|
end
|
|
|
|
-- from = room.jid so the stanza routes through ChatRoom.onMessage in
|
|
-- lib-jitsi-meet (which only processes messages whose bare from matches the
|
|
-- room) and is emitted as JSON_MESSAGE_RECEIVED -> NON_PARTICIPANT_MESSAGE_RECEIVED.
|
|
local stanza = st.message({ from = room.jid; to = to_jid; })
|
|
:tag('json-message', { xmlns = 'http://jitsi.org/jitmeet' }):text(body):up();
|
|
module:send(stanza);
|
|
end
|
|
|
|
module:hook("muc-room-created", function (event)
|
|
local room = event.room
|
|
|
|
if is_healthcheck_room(room.jid) then
|
|
return
|
|
end
|
|
|
|
room.time_restricted_created = os.time();
|
|
|
|
room.destroy_timer = module:add_timer(DESTROY_AT, function()
|
|
if is_healthcheck_room(room.jid) then
|
|
return
|
|
end
|
|
restricted_rooms[room.jid] = true;
|
|
-- %g (not %d) so a fractional conference_max_minutes does not crash the
|
|
-- timer; for the usual whole-minute configs it renders identically.
|
|
room:destroy(nil, string.format('This meeting reached its %g-minute time limit and has ended.', MIN));
|
|
|
|
module:log('info', "the conference terminated %s", room.jid);
|
|
end)
|
|
end)
|
|
|
|
-- Every occupant is told the meeting's limit as soon as they join, so the
|
|
-- client holds the full picture from the start and decides for itself when to
|
|
-- surface it (`timeTimer.suppressForSeconds` in jitsi-meet delays the visible
|
|
-- countdown by a configurable number of seconds). `elapsedSeconds` keeps late
|
|
-- joiners in sync with everyone else.
|
|
module:hook("muc-occupant-joined", function (event)
|
|
local room, occupant = event.room, event.occupant;
|
|
|
|
if is_healthcheck_room(room.jid) then
|
|
return
|
|
end
|
|
|
|
-- Only for rooms this module saw created: without a creation stamp we
|
|
-- cannot say how far in the meeting is, and reporting elapsed = 0 for a
|
|
-- room that has been running for a while would be worse than saying
|
|
-- nothing.
|
|
if room.time_restricted_created then
|
|
send_time_timer(room, occupant.jid);
|
|
end
|
|
end);
|
|
|
|
module:hook("muc-room-pre-create", function(event)
|
|
local origin, stanza, room = event.origin, event.stanza, event.room;
|
|
|
|
if is_healthcheck_room(room.jid) then
|
|
return
|
|
end
|
|
|
|
if restricted_rooms[room.jid] then
|
|
module:log('info', "the conference id blocked %s", room.jid);
|
|
origin.send(st.error_reply(stanza, "cancel", "resource-constraint", nil, module.host));
|
|
return true;
|
|
end
|
|
end, 200);
|
|
|
|
module:hook('muc-room-destroyed',function(event)
|
|
local room = event.room;
|
|
if room.destroy_timer then
|
|
room.destroy_timer:stop();
|
|
room.destroy_timer = nil;
|
|
end
|
|
end, 1); -- prosody handles it at 0
|