snapshot of https://github.com/jitsi/jitsi-meet.git @ fd1749dd28f4138aa80234fc7f311b19aaffa0e7 (2026-09-15)
This commit is contained in:
116
resources/prosody-plugins/mod_time_restricted.lua
Normal file
116
resources/prosody-plugins/mod_time_restricted.lua
Normal file
@@ -0,0 +1,116 @@
|
||||
--- 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
|
||||
Reference in New Issue
Block a user