Destroy the room after the last moderator leaves (prosody custom module)

This module destroys the room if the last moderator left (secure domain)
Timeout is configurable (in seconds).
If the moderator (re)joins within the specified timeout, the room will not be closed.

  1. Make a new script file “mod_disconnect.lua” in the Prosody plugins folder (/usr/share/jitsi-meet/prosody-plugins/)
local LOGLEVEL = "debug"
local MIN = module:get_option_number("conference_timeout", 10)
local TIMEOUT = MIN

local is_healthcheck_room = module:require "util".is_healthcheck_room
local st = require "util.stanza"
local timer = require "util.timer"
module:log(LOGLEVEL, "loaded")

module:hook("muc-occupant-left", function (event)
    local room = event.room
    local mods = room:each_affiliation("owner");
    local leaver = event.occupant.bare_jid;
    local a = 0;
    local b = 0;

    for mod in mods do
        a = a + 1;
        if mod == leaver then
            room:set_affiliation(true, leaver, "outcast");
            a = a - 1;
        end
    end

  for mod in mods do
        module:log("info", "mods: %s", a);
        if a == 1 then

            if is_healthcheck_room(room.jid) then
                module:log(LOGLEVEL, "skip restriction")
                return
            end

            room:broadcast_message(
                 st.message({ type="groupchat", from=room.jid })
                 :tag("body")
                 :text("The conference will be terminated in "..MIN.." sec"))

            module:log(LOGLEVEL, "set timeout for conference, %s secs, %s",
                                 TIMEOUT, room.jid)

            timer.add_task(TIMEOUT, function()
                if is_healthcheck_room(room.jid) then
                    return
                end

                for mod in mods do
                    b = b + 1;
                end

                if b == 1 then
                   for _, p in room:each_occupant() do
                       room:set_affiliation(true, p.jid, "outcast")
                       module:log("info", "kick the occupant, %s", p.jid)
                       module:log("info", "the conference terminated")
                   end
                else
                   module:log("info", "still a moderator present");
                   room:broadcast_message(
                     st.message({ type="groupchat", from=room.jid })
                     :tag("body")
                     :text("The moderator has joined. The termination of the conference was canceled."))
                end
            end)
        end
    end
end)
  1. Enable module in your prosody config (/etc/prosody/conf.d/meet.mydomain.com.cfg.lua)
    search for:
    Component “conference.meet.mydomain.com” “muc”
    modules_enabled = {


    “disconnect”;
    }
    conference_timeout = 15

Restart the services
systemctl restart prosody.service
systemctl restart jicofo.service

3 Likes

update:
after destroying the room, users will receive a message
изображение

local LOGLEVEL = "debug"
local MIN = module:get_option_number("conference_timeout", 10)
local TIMEOUT = MIN

local is_healthcheck_room = module:require "util".is_healthcheck_room
local st = require "util.stanza"
local timer = require "util.timer"
module:log(LOGLEVEL, "loaded")

module:hook("muc-occupant-left", function (event)
    local room = event.room
    local mods = room:each_affiliation("owner");
    local leaver = event.occupant.bare_jid;
    local a = 0;
    local b = 0;

    for mod in mods do
        a = a + 1;
        if mod == leaver then
            room:set_affiliation(true, leaver, "outcast");
            module:log("info", "still a moderator present");
            a = a - 1;
        end
    end

  for mod in mods do
        module:log("info", "mods: %s", a);
        if a == 1 then

            if is_healthcheck_room(room.jid) then
                module:log(LOGLEVEL, "skip restriction")
                return
            end

            room:broadcast_message(
                 st.message({ type="groupchat", from=room.jid })
                 :tag("body")
                 :text("The conference will be terminated in "..MIN.." sec"))

            module:log(LOGLEVEL, "set timeout for conference, %s secs, %s",
                                 TIMEOUT, room.jid)

            timer.add_task(TIMEOUT, function()
                if is_healthcheck_room(room.jid) then
                    return
                end

                for mod in mods do
                    b = b + 1;
                end

                if b == 1 then
                   event.room:destroy();
                   for _, p in room:each_occupant() do
                       room:set_affiliation(true, p.jid, "outcast")
                       module:log("info", "kick the occupant, %s", p.jid)
                       module:log("info", "the conference terminated")
                   end
                else
                   module:log("info", "still a moderator present");
                   room:broadcast_message(
                     st.message({ type="groupchat", from=room.jid })
                     :tag("body")
                     :text("A moderator has joined. The termination of the conference was canceled."))
                end
            end)
        end
    end
end)
3 Likes

This updated lua does not seem to work in my testing. The call terminated message is received, but the room is never destroyed. If the moderator tries to create/join the same room again, there is a “connection failed” error with no obvious error logs in prosody even in jicofo and jvb.

Prosody’s version is 0.11.4-1.

The previous “mod_disconnect.lua” works though.

I don’t have such a problem.
after receiving the call terminated message, the conference time continues to run. but the conference is destroyed. and the moderator can create a new conference with the same name.
and if the moderator reconnects to the same conference before receiving the message, everything is ok too …

try updating prosody to the latest version.
I have 0.11.10-1

Hi. Thanks for the reply.
I upgraded prosody as recommended and now using the same version you posted but it’s the same.
Does it matter if I am using unstable?

Still, the 1st lua script you posted, the one without the “event.room:destroy()” function works.

Kind regards,

I confirm that in the latest version of jitsi meet “event.room:destroy()” does not work as expected…
I’ll see what I can do.
The first version in the header (without “event.room:destroy()”) works without any problems.

ok… update:

screenshots


updated code
local LOGLEVEL = "debug"
local MIN = module:get_option_number("conference_timeout", 10)
local TIMEOUT = MIN

local is_healthcheck_room = module:require "util".is_healthcheck_room
local st = require "util.stanza"
local timer = require "util.timer"
module:log(LOGLEVEL, "loaded")

module:hook("muc-occupant-left", function (event)
    local room = event.room
    local mods = room:each_affiliation("owner");
    local leaver = event.occupant.bare_jid;
    local a = 0;
    local b = 0;

    for mod in mods do
        a = a + 1;
        if mod == leaver then
            room:set_affiliation(true, leaver, "outcast");
            module:log("info", "still a moderator present");
            a = a - 1;
        end
    end

  for mod in mods do
        module:log("info", "mods: %s", a);
        if a == 1 then

            if is_healthcheck_room(room.jid) then
                module:log(LOGLEVEL, "skip restriction")
                return
            end

            room:broadcast_message(
                 st.message({ type="groupchat", from=room.jid })
                 :tag("subject")
                 :text("The conference will be terminated in "..MIN.." sec"))

            module:log(LOGLEVEL, "set timeout for conference, %s secs, %s",
                                 TIMEOUT, room.jid)

            timer.add_task(TIMEOUT, function()
                if is_healthcheck_room(room.jid) then
                    return
                end

                for mod in mods do
                    b = b + 1;
                end

                if b == 1 then

                   room:broadcast_message(
                       st.message({ type="groupchat", from=room.jid })
                       :tag("subject")
                       :text("THE CONFERENCE IS OVER"))
                       local start = os.clock()
                       while os.clock() - start < 3 do end

                   for _, p in room:each_occupant() do
                       room:set_affiliation(true, p.jid, "outcast")
                       module:log("info", "kick the occupant, %s", p.jid)
                       module:log("info", "the conference terminated")
                   end
                else
                   module:log("info", "still a moderator present");
                   room:broadcast_message(
                     st.message({ type="groupchat", from=room.jid })
                     :tag("subject")
                     :text(roomName))
                end
            end)
        end
    end
end)
2 Likes

slightly corrected the code in the previous post.
if the moderator has rejoined, the upper message about the termination of the conference is changed to the name of the room.