Mod_muc_size module problem in docker using lib-jitsi-meet

@saghul can u help me in this case? I tried so many times bt failed :cry:

I don’t know off the top of my head, sorry. Once I find some time to test this I’ll let you know.

ok thanx and plz make me know… I failed to get appropriate results

@saghul did u get any time to look into docker muc_size module? sorry for early asking… and
Thanx in advance :heart:

No I didn’ t have the time, sorry.

It’s ok, waiting :heart:

@Fuji

Hello. I had same issue, but I finally figured out how to work room-size by using compose ( https://github.com/jitsi/docker-jitsi-meet ) .

  1. Please set meet.conf of /room-size as below:
    location /room-size {
        proxy_pass http://xmpp.meet.jitsi:5280/room-size?$args&domain=meet.jitsi;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Host meet.jitsi;
    }
  1. Add below line to prosody.cfg.lua (because default value of muc_mapper_domain_prefix is different from compose’s config! ) :
    muc_mapper_domain_prefix = "muc"

I hope I can help you.

1 Like

I will give a try soon and really thanx for sharing :heart:

@jenus

muc_mapper_domain_prefix = "muc"

is this because of the default value “conference” ? and domain = meet.jitsi completely make sense :heart: and I solved a issue with changing domain name and muc domain (libjitsi meet api calling to docker jitsi server)
but I am stille having problem,same error as before…

here is my meet.conf in /web/nginx/ :
server_name _;

client_max_body_size 0;

root /usr/share/jitsi-meet;
index index.html
error_page 404 /static/404.html;

location ~ ^/([a-zA-Z0-9=\?]+)$ {
    rewrite ^/(.*)$ / break;
}

location /config.js {
    alias /config/config.js;
}

location /interface_config.js {
    alias /config/interface_config.js;
}

location /external_api.js {
    alias /usr/share/jitsi-meet/libs/external_api.min.js;
}

location / {
    ssi on;
}

# BOSH
location /http-bind {

    
#    add_header 'Access-Control-Allow-Methods' '*';
#    add_header 'Access-Control-Allow-Headers' '*';
#    add_header 'Access-Control-Allow-Origin' '*';
 
    
    proxy_pass http://xmpp.meet.jitsi:5280/http-bind;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header Host meet.jitsi;

}


location /room-size {
        proxy_pass http://xmpp.meet.jitsi:5280/room-size?$args&domain=meet.jitsi;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Host meet.jitsi;
    }

here is my prosody.cfg.lua in /prosody/ :
admins = { }

-- Enable use of libevent for better performance under high load
-- For more information see: http://prosody.im/doc/libevent
--use_libevent = true;

-- This is the list of modules Prosody will load on startup.
-- It looks for mod_modulename.lua in the plugins folder, so make sure that exists too.
-- Documentation on modules can be found at: http://prosody.im/doc/modules
modules_enabled = {
		"muc_size";
	-- Generally required
		"roster"; -- Allow users to have a roster. Recommended ;)
		"saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
		"tls"; -- Add support for secure TLS on c2s/s2s connections
		"dialback"; -- s2s dialback support
		"disco"; -- Service discovery

	-- Not essential, but recommended
		"private"; -- Private XML storage (for room bookmarks, etc.)
		"vcard"; -- Allow users to set vCards
	
	-- These are commented by default as they have a performance impact
		--"privacy"; -- Support privacy lists
		--"compression"; -- Stream compression (Debian: requires lua-zlib module to work)

	-- Nice to have
		"version"; -- Replies to server version requests
		"uptime"; -- Report how long server has been running
		"time"; -- Let others know the time here on this server
		"ping"; -- Replies to XMPP pings with pongs
		"pep"; -- Enables users to publish their mood, activity, playing music and more
		"register"; -- Allow users to register on this server using a client and change passwords

	-- Admin interfaces
		"admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands
		--"admin_telnet"; -- Opens telnet console interface on localhost port 5582
	
	-- HTTP modules
		--"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP"
		--"http_files"; -- Serve static files from a directory over HTTP

	-- Other specific functionality
		"posix"; -- POSIX functionality, sends server to background, enables syslog, etc.
		--"groups"; -- Shared roster support
		--"announce"; -- Send announcement to all online users
		--"welcome"; -- Welcome users who register accounts
		--"watchregistrations"; -- Alert admins of registrations
		--"motd"; -- Send a message to users when they log in
		--"legacyauth"; -- Legacy authentication. Only used by some old clients and bots.
        
};

https_ports = { }

-- These modules are auto-loaded, but should you want
-- to disable them then uncomment them here:
modules_disabled = {
	-- "offline"; -- Store offline messages
	-- "c2s"; -- Handle client connections
	-- "s2s"; -- Handle server-to-server connections
};

enable_roomsize_token_verification=false;

-- Disable account creation by default, for security
-- For more information see http://prosody.im/doc/creating_accounts
allow_registration = false;

daemonize = false;

pidfile = "/config/data/prosody.pid";


-- Force clients to use encrypted connections? This option will
-- prevent clients from authenticating unless they are using encryption.

c2s_require_encryption = false;


--The traditional solution to solving the same-origin problem is to have the web server that serves the app script also act as a proxy to the real BOSH server at some URL.
consider_bosh_secure = true

--There is a relatively new HTTP extension that allows web servers to tell browsers that cross-domain requests are ok and permitted, called CORS.
cross_domain_bosh = true

-- Force certificate authentication for server-to-server connections?
-- This provides ideal security, but requires servers you communicate
-- with to support encryption AND present valid, trusted certificates.
-- NOTE: Your version of LuaSec must support certificate verification!
-- For more information see http://prosody.im/doc/s2s#security

s2s_secure_auth = false;

-- Many servers don't support encryption or have invalid or self-signed
-- certificates. You can list domains here that will not be required to
-- authenticate using certificates. They will be authenticated using DNS.

--s2s_insecure_domains = { "gmail.com" }

-- Even if you leave s2s_secure_auth disabled, you can still require valid
-- certificates for some domains by specifying a list here.

--s2s_secure_domains = { "jabber.org" }

-- Select the authentication backend to use. The 'internal' providers
-- use Prosody's configured data storage to store the authentication data.
-- To allow Prosody to offer secure authentication mechanisms to clients, the
-- default provider stores passwords in plaintext. If you do not trust your
-- server please see http://prosody.im/doc/modules/mod_auth_internal_hashed
-- for information about using the hashed backend.

authentication = "internal_plain";

-- Select the storage backend to use. By default Prosody uses flat files
-- in its configured data directory, but it also supports more backends
-- through modules. An "sql" backend is included by default, but requires
-- additional dependencies. See http://prosody.im/doc/storage for more info.

--storage = "sql" -- Default is "internal" (Debian: "sql" requires one of the
-- lua-dbi-sqlite3, lua-dbi-mysql or lua-dbi-postgresql packages to work)

-- For the "sql" backend, you can uncomment *one* of the below to configure:
--sql = { driver = "SQLite3", database = "prosody.sqlite" } -- Default. 'database' is the filename.
--sql = { driver = "MySQL", database = "prosody", username = "prosody", password = "secret", host = "localhost" }
--sql = { driver = "PostgreSQL", database = "prosody", username = "prosody", password = "secret", host = "localhost" }

-- Logging configuration
-- For advanced logging see http://prosody.im/doc/logging
--
-- Debian:
--  Logs info and higher to /var/log
--  Logs errors to syslog also

muc_mapper_domain_prefix = "muc"



log = {
	{ levels = {min = "info"}, to = "console"};
}



component_interface = { "*" }

data_path = "/config/data"

Include "conf.d/*.cfg.lua"
here is my mod_mic_size.lua :
-- Prosody IM
-- Copyright (C) 2017 Atlassian
--

local jid = require "util.jid";
local it = require "util.iterators";
local json = require "util.json";
local iterators = require "util.iterators";
local array = require"util.array";
local wrap_async_run = module:require "util".wrap_async_run;

local tostring = tostring;
local neturl = require "net.url";
local parse = neturl.parseQuery;

-- option to enable/disable room API token verifications
local enableTokenVerification
    = module:get_option_boolean("enable_roomsize_token_verification", false);

local token_util = module:require "token/util".new(module);
local get_room_from_jid = module:require "util".get_room_from_jid;

-- no token configuration but required
if token_util == nil and enableTokenVerification then
    log("error", "no token configuration but it is required");
    return;
end

-- required parameter for custom muc component prefix,
-- defaults to "conference"
local muc_domain_prefix
    = module:get_option_string("muc_mapper_domain_prefix", "conference");

--- Verifies room name, domain name with the values in the token
-- @param token the token we received
-- @param room_address the full room address jid
-- @return true if values are ok or false otherwise
function verify_token(token, room_address)
    if not enableTokenVerification then
        return true;
    end

    -- if enableTokenVerification is enabled and we do not have token
    -- stop here, cause the main virtual host can have guest access enabled
    -- (allowEmptyToken = true) and we will allow access to rooms info without
    -- a token
    if token == nil then
        log("warn", "no token provided");
        return false;
    end

    local session = {};
    session.auth_token = token;
    local verified, reason = token_util:process_and_verify_token(session);
    if not verified then
        log("warn", "not a valid token %s", tostring(reason));
        return false;
    end

    if not token_util:verify_room(session, room_address) then
        log("warn", "Token %s not allowed to join: %s",
            tostring(token), tostring(room_address));
        return false;
    end

    return true;
end

--- Handles request for retrieving the room size
-- @param event the http event, holds the request query
-- @return GET response, containing a json with participants count,
--         tha value is without counting the focus.
function handle_get_room_size(event)
    if (not event.request.url.query) then
        return 400;
    end

	local params = parse(event.request.url.query);
	local room_name = params["room"];
	local domain_name = params["domain"];
    local subdomain = params["subdomain"];

    local room_address
        = jid.join(room_name, muc_domain_prefix.."."..domain_name);

    if subdomain and subdomain ~= "" then
        room_address = "["..subdomain.."]"..room_address;
    end

    if not verify_token(params["token"], room_address) then
        return 403;
    end

	local room = get_room_from_jid(room_address);
	local participant_count = 0;

	log("debug", "Querying room %s", tostring(room_address));

	if room then
		local occupants = room._occupants;
		if occupants then
			participant_count = iterators.count(room:each_occupant());
		end
		log("debug",
            "there are %s occupants in room", tostring(participant_count));
	else
		log("debug", "no such room exists");
		return 404;
	end

	if participant_count > 1 then
		participant_count = participant_count - 1;
	end

	return [[{"participants":]]..participant_count..[[}]];
end

--- Handles request for retrieving the room participants details
-- @param event the http event, holds the request query
-- @return GET response, containing a json with participants details
function handle_get_room (event)
    if (not event.request.url.query) then
        return 400;
    end

	local params = parse(event.request.url.query);
	local room_name = params["room"];
	local domain_name = params["domain"];
    local subdomain = params["subdomain"];
    local room_address
        = jid.join(room_name, muc_domain_prefix.."."..domain_name);

    if subdomain ~= "" then
        room_address = "["..subdomain.."]"..room_address;
    end

    if not verify_token(params["token"], room_address) then
        return 403;
    end

	local room = get_room_from_jid(room_address);
	local participant_count = 0;
	local occupants_json = array();

	log("debug", "Querying room %s", tostring(room_address));

	if room then
		local occupants = room._occupants;
		if occupants then
			participant_count = iterators.count(room:each_occupant());
			for _, occupant in room:each_occupant() do
			    -- filter focus as we keep it as hidden participant
			    if string.sub(occupant.nick,-string.len("/focus"))~="/focus" then
				    for _, pr in occupant:each_session() do
					local nick = pr:get_child_text("nick", "http://jabber.org/protocol/nick") or "";
					local email = pr:get_child_text("email") or "";
					occupants_json:push({
					    jid = tostring(occupant.nick),
					    email = tostring(email),
					    display_name = tostring(nick)});
				    end
			    end
			end
		end
		log("debug",
            "there are %s occupants in room", tostring(participant_count));
	else
		log("debug", "no such room exists");
		return 404;
	end

	if participant_count > 1 then
		participant_count = participant_count - 1;
	end

	return json.encode(occupants_json);
end;

function tablelength(T)
        local hash = {}
        local res = {}

        for _,v in ipairs(T) do
           if (not hash[v]) then
               res[#res+1] = v
               hash[v] = true
           end
        end

        local count = 0
        for _ in pairs(res) do count = count + 1 end
        return count
end

function getNbConfPart() 
    local tab={};

    --conferences count (without eliminating duplicates )
    for key, value in pairs(prosody.full_sessions) do
            if tostring(value["username"]:lower()) ~= "focus" then
                    table.insert(tab,tostring(value["jitsi_meet_room"]:lower()));
            end
    end

    local nbPart = 0
    if it.count(it.keys(prosody.full_sessions))-1 >= 0 --participants count
            then nbPart= it.count(it.keys(prosody.full_sessions))-1
    end

    local nbConf = tablelength(tab) --conferences count
    if nbPart == 0
            then nbConf=0
    end

     --create result as json
    local result_json=array();
    result_json:push({
                    part= nbPart,
                    conf=tablelength(tab) -- eliminates count number of rooms
            });

    -- create json response 
    return json.encode(result_json);
end

function has_value(tab, val)
   for _, value in ipairs(tab) do
       if value == val then
           return true
       end
   end
   return false
end

function get_info_rooms()
   local innerValues = {};
   local keyRoom = "jitsi_bosh_query_room";
   for _, value in pairs(prosody.full_sessions) do
       if tostring(value["username"]:lower()) ~= "focus" then
           for innerKey, innerValue in pairs(value) do
               if innerKey == keyRoom and not has_value(innerValues, innerValue) then
                   table.insert(innerValues, innerValue)
               end
           end
       end
   end
return json.encode(innerValues);
end

function module.load()
    module:depends("http");
	module:provides("http", {
		default_path = "/";
		route = {
			["GET room-size"] = function (event) return wrap_async_run(event,handle_get_room_size) end;
			["GET sessions"] = function () return tostring(it.count(it.keys(prosody.full_sessions))); end;
			["GET room"] = function (event) return wrap_async_run(event,handle_get_room) end;
			["GET nbConfPart"] = function (event) return wrap_async_run(event,getNbConfPart) end;
                       ["GET get-info-rooms"] = function (event) return wrap_async_run(event,get_info_rooms) end;
		};
	});
end

It would be nice to see urs…!
I hosted the server in https://fuji where I set fuji for 192.168.0.149 (my local ip) in /etc/hosts
I even commented out the proxy passing things like commenting “location /room-size{}” but I am still getting same result :confused: I am really confused here… is the proxy passing thing even working? or it just outside the docker network? how can I check?
I am getting results by going to
192.168.0.149:5280/sessions or 192.168.0.149:5280/room-size?room=aa
by going to “https://fuji/sessions” or “https://fuji/room-size?room=aa” doesnt work (this should work…!)
or can u just elaborate what u did as it would be really great to know the details :heart:
Thanx in advance :sparkling_heart:

may be I did something wrong…! but now “/room-size” is working :heart:
muc
but /room or others isnt working… is this the write way to do it?

my meet.conf now :
server_name _;

client_max_body_size 0;

root /usr/share/jitsi-meet;
index index.html
error_page 404 /static/404.html;

location ~ ^/([a-zA-Z0-9=\?]+)$ {
    rewrite ^/(.*)$ / break;
}

location /config.js {
    alias /config/config.js;
}

location /interface_config.js {
    alias /config/interface_config.js;
}

location /external_api.js {
    alias /usr/share/jitsi-meet/libs/external_api.min.js;
}

location / {
    ssi on;
}

# BOSH
location /http-bind {

    
#    add_header 'Access-Control-Allow-Methods' '*';
#    add_header 'Access-Control-Allow-Headers' '*';
#    add_header 'Access-Control-Allow-Origin' '*';
 
    
    proxy_pass http://xmpp.meet.jitsi:5280/http-bind;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header Host meet.jitsi;
    


}

location /room-size {
        
	proxy_pass http://xmpp.meet.jitsi:5280/room-size?$args&domain=meet.jitsi;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Host meet.jitsi;

    }

location /room {
        
	proxy_pass http://xmpp.meet.jitsi:5280/room?$args&domain=meet.jitsi;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Host meet.jitsi;

    }

location /nbConfPart {
        
	proxy_pass http://xmpp.meet.jitsi:5280/nbConfPart;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Host meet.jitsi;

    }

location /get-info-rooms {
        
	proxy_pass http://xmpp.meet.jitsi:5280/get-info-rooms;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Host meet.jitsi;

    }

location /sessions {
        
	proxy_pass http://xmpp.meet.jitsi:5280/sessions;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Host meet.jitsi;

    }

Nearly same problem here

  • /sessions => ok
  • /get-info-room => ok
  • /nbConfPart => 500

my prosody err log :

runnerdz-06dQP  error   Encountered error: /usr/share/jitsi-meet/prosody-plugins/mod_muc_size.lua:201: attempt to index field 'jitsi_meet_room' (a nil value)
stack traceback:
    /usr/share/jitsi-meet/prosody-plugins/mod_muc_size.lua:201: in function 'handler'
    /usr/share/jitsi-meet/prosody-plugins/util.lib.lua:69: in function 'func'
    /usr/lib/prosody/util/async.lua:127: in function </usr/lib/prosody/util/async.lua:125>
Mar 19 15:46:09 http.server     error   Traceback[httpserver]: /usr/lib/prosody/util/async.lua:137: /usr/share/jitsi-meet/prosody-plugins/mod_muc_size.lua:201: attempt to index field 'jitsi_meet_room' (a
nil value)
stack traceback:
    /usr/share/jitsi-meet/prosody-plugins/mod_muc_size.lua:201: in function 'handler'
    /usr/share/jitsi-meet/prosody-plugins/util.lib.lua:69: in function 'func'
    /usr/lib/prosody/util/async.lua:127: in function </usr/lib/prosody/util/async.lua:125>
stack traceback:
    [C]: in function 'error'
    /usr/lib/prosody/util/async.lua:137: in function 'handler'
    /usr/lib/prosody/util/async.lua:211: in function 'run'
    /usr/share/jitsi-meet/prosody-plugins/util.lib.lua:80: in function </usr/share/jitsi-meet/prosody-plugins/util.lib.lua:64>
    (...tail calls...)
    /usr/lib/prosody/util/events.lua:79: in function </usr/lib/prosody/util/events.lua:75>
    (...tail calls...)
    /usr/lib/prosody/net/http/server.lua:248: in function </usr/lib/prosody/net/http/server.lua:176>
    [C]: in function 'xpcall'
    /usr/lib/prosody/net/http/server.lua:108: in function 'process_next'
    /usr/lib/prosody/net/http/server.lua:124: in function 'success_cb'
    /usr/lib/prosody/net/http/parser.lua:177: in function 'feed'
    /usr/lib/prosody/net/http/server.lua:155: in function </usr/lib/prosody/net/http/server.lua:154>
    (...tail calls...)
    /usr/lib/prosody/net/server_select.lua:915: in function </usr/lib/prosody/net/server_select.lua:899>
    [C]: in function 'xpcall'
    /usr/bin/prosody:80: in function 'loop'
    /usr/bin/prosody:90: in main chunk
    [C]: in ?

Im running apache2

any idea ?

may b ur pb is in the mod_muc_size module… look at the error and just track… then after muc_size go to util.lib.lua and check… where it is crashing… may be it cant find some prerequisite things that I am not sure… I had problems regarding prerequisite installations… but nice to hear that “get-info-room” is working… :slight_smile: mine isn’t and I am using docker…

By default, nginx proxies request for alphabetical path to frontend (see here) :

location ~ ^/([a-zA-Z0-9=\?]+)$ {
    rewrite ^/(.*)$ / break;
}

So, you should change from

location /room {

to

location /room-info {

then it might work. Please try it.

1 Like

yeah, it is working fine after changing to "room-info’ and I also had to change in mod_muc_size.lua after getting error… can u provide a correct mod_muc_size.lua with all of this working?
right now “/room-size”, “/room-info” and “/sessions-info” is working :heartbeat:

my meet.conf
server_name _;

client_max_body_size 0;

root /usr/share/jitsi-meet;
index index.html
error_page 404 /static/404.html;

location ~ ^/([a-zA-Z0-9=\?]+)$ {
    rewrite ^/(.*)$ / break;
}

location /config.js {
    alias /config/config.js;
}

location /interface_config.js {
    alias /config/interface_config.js;
}

location /external_api.js {
    alias /usr/share/jitsi-meet/libs/external_api.min.js;
}

location / {
    ssi on;
}

# BOSH
location /http-bind {

    
#    add_header 'Access-Control-Allow-Methods' '*';
#    add_header 'Access-Control-Allow-Headers' '*';
#    add_header 'Access-Control-Allow-Origin' '*';
 
    
    proxy_pass http://xmpp.meet.jitsi:5280/http-bind;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header Host meet.jitsi;
    


}

#muc_size
 location /get-info-rooms {
     proxy_pass http://xmpp.meet.jitsi:5280/get-info-rooms?domain=meet.jitsi;
     proxy_set_header X-Forwarded-For $remote_addr;
     proxy_set_header Host meet.jitsi;

 }

 location /nbConfPart-info {
     proxy_pass http://xmpp.meet.jitsi:5280/nbConfPart?domain=meet.jitsi;
     proxy_set_header X-Forwarded-For $remote_addr;
     proxy_set_header Host meet.jitsi;
     add_header 'Access-Control-Allow-Origin' '*';

 }

 location /room-size {
     proxy_pass http://xmpp.meet.jitsi:5280/room-size?$args&domain=meet.jitsi;
     proxy_set_header X-Forwarded-For $remote_addr;
     proxy_set_header Host meet.jitsi;

 }

 location /room-info {
     proxy_pass http://xmpp.meet.jitsi:5280/room?$args&domain=meet.jitsi;
     proxy_set_header X-Forwarded-For $remote_addr;
     proxy_set_header Host meet.jitsi;

 }

 location /sessions-info {
     proxy_pass http://xmpp.meet.jitsi:5280/sessions?domain=meet.jitsi;
     proxy_set_header X-Forwarded-For $remote_addr;
     proxy_set_header Host meet.jitsi;

 }
my mod_muc_size.lua
-- Prosody IM
-- Copyright (C) 2017 Atlassian
--

local jid = require "util.jid";
local it = require "util.iterators";
local json = require "util.json";
local iterators = require "util.iterators";
local array = require"util.array";
local wrap_async_run = module:require "util".wrap_async_run;

local tostring = tostring;
local neturl = require "net.url";
local parse = neturl.parseQuery;

-- option to enable/disable room API token verifications
local enableTokenVerification
    = module:get_option_boolean("enable_roomsize_token_verification", false);

local token_util = module:require "token/util".new(module);
local get_room_from_jid = module:require "util".get_room_from_jid;

-- no token configuration but required
if token_util == nil and enableTokenVerification then
    log("error", "no token configuration but it is required");
    return;
end

-- required parameter for custom muc component prefix,
-- defaults to "conference"
local muc_domain_prefix
    = module:get_option_string("muc_mapper_domain_prefix", "conference");

--- Verifies room name, domain name with the values in the token
-- @param token the token we received
-- @param room_address the full room address jid
-- @return true if values are ok or false otherwise
function verify_token(token, room_address)
    if not enableTokenVerification then
        return true;
    end

    -- if enableTokenVerification is enabled and we do not have token
    -- stop here, cause the main virtual host can have guest access enabled
    -- (allowEmptyToken = true) and we will allow access to rooms info without
    -- a token
    if token == nil then
        log("warn", "no token provided");
        return false;
    end

    local session = {};
    session.auth_token = token;
    local verified, reason = token_util:process_and_verify_token(session);
    if not verified then
        log("warn", "not a valid token %s", tostring(reason));
        return false;
    end

    if not token_util:verify_room(session, room_address) then
        log("warn", "Token %s not allowed to join: %s",
            tostring(token), tostring(room_address));
        return false;
    end

    return true;
end

--- Handles request for retrieving the room size
-- @param event the http event, holds the request query
-- @return GET response, containing a json with participants count,
--         tha value is without counting the focus.
function handle_get_room_size(event)
    if (not event.request.url.query) then
        return 400;
    end

	local params = parse(event.request.url.query);
	local room_name = params["room"];
	local domain_name = params["domain"];
    local subdomain = params["subdomain"];

    local room_address
        = jid.join(room_name, muc_domain_prefix.."."..domain_name);

    if subdomain and subdomain ~= "" then
        room_address = "["..subdomain.."]"..room_address;
    end

    if not verify_token(params["token"], room_address) then
        return 403;
    end

	local room = get_room_from_jid(room_address);
	local participant_count = 0;

	log("debug", "Querying room %s", tostring(room_address));

	if room then
		local occupants = room._occupants;
		if occupants then
			participant_count = iterators.count(room:each_occupant());
		end
		log("debug",
            "there are %s occupants in room", tostring(participant_count));
	else
		log("debug", "no such room exists");
		return 404;
	end

	if participant_count > 1 then
		participant_count = participant_count - 1;
	end

	return [[{"participants":]]..participant_count..[[}]];
end

--- Handles request for retrieving the room participants details
-- @param event the http event, holds the request query
-- @return GET response, containing a json with participants details
function handle_get_room (event)
    if (not event.request.url.query) then
        return 400;
    end

	local params = parse(event.request.url.query);
	local room_name = params["room"];
	local domain_name = params["domain"];
    local subdomain = params["subdomain"];
    local room_address
        = jid.join(room_name, muc_domain_prefix.."."..domain_name);

    if subdomain and subdomain ~= "" then
        room_address = "["..subdomain.."]"..room_address;
    end

    if not verify_token(params["token"], room_address) then
        return 403;
    end

	local room = get_room_from_jid(room_address);
	local participant_count = 0;
	local occupants_json = array();

	log("debug", "Querying room %s", tostring(room_address));

	if room then
		local occupants = room._occupants;
		if occupants then
			participant_count = iterators.count(room:each_occupant());
			for _, occupant in room:each_occupant() do
			    -- filter focus as we keep it as hidden participant
			    if string.sub(occupant.nick,-string.len("/focus"))~="/focus" then
				    for _, pr in occupant:each_session() do
					local nick = pr:get_child_text("nick", "http://jabber.org/protocol/nick") or "";
					local email = pr:get_child_text("email") or "";
					occupants_json:push({
					    jid = tostring(occupant.nick),
					    email = tostring(email),
					    display_name = tostring(nick)});
				    end
			    end
			end
		end
		log("debug",
            "there are %s occupants in room", tostring(participant_count));
	else
		log("debug", "no such room exists");
		return 404;
	end

	if participant_count > 1 then
		participant_count = participant_count - 1;
	end

	return json.encode(occupants_json);
end;

function tablelength(T)
        local hash = {}
        local res = {}

        for _,v in ipairs(T) do
           if (not hash[v]) then
               res[#res+1] = v
               hash[v] = true
           end
        end

        local count = 0
        for _ in pairs(res) do count = count + 1 end
        return count
end

function getNbConfPart() 
    local tab={};

    --conferences count (without eliminating duplicates )
    for key, value in pairs(prosody.full_sessions) do
            if tostring(value["username"]:lower()) ~= "focus" then
                    table.insert(tab,tostring(value["jitsi_meet_room"]:lower()));
            end
    end

    local nbPart = 0
    if it.count(it.keys(prosody.full_sessions))-1 >= 0 --participants count
            then nbPart= it.count(it.keys(prosody.full_sessions))-1
    end

    local nbConf = tablelength(tab) --conferences count
    if nbPart == 0
            then nbConf=0
    end

     --create result as json
    local result_json=array();
    result_json:push({
                    part= nbPart,
                    conf=tablelength(tab) -- eliminates count number of rooms
            });

    -- create json response 
    return json.encode(result_json);
end

function has_value(tab, val)
   for _, value in ipairs(tab) do
       if value == val then
           return true
       end
   end
   return false
end

function get_info_rooms()
   local innerValues = {};
   local keyRoom = "jitsi_bosh_query_room";
   for _, value in pairs(prosody.full_sessions) do
       if tostring(value["username"]:lower()) ~= "focus" then
           for innerKey, innerValue in pairs(value) do
               if innerKey == keyRoom and not has_value(innerValues, innerValue) then
                   table.insert(innerValues, innerValue)
               end
           end
       end
   end
return json.encode(innerValues);
end

function module.load()
    module:depends("http");
	module:provides("http", {
		default_path = "/";
		route = {
			["GET room-size"] = function (event) return wrap_async_run(event,handle_get_room_size) end;
			["GET sessions"] = function () return tostring(it.count(it.keys(prosody.full_sessions))); end;
			["GET room"] = function (event) return wrap_async_run(event,handle_get_room) end;
			["GET nbConfPart"] = function (event) return wrap_async_run(event,getNbConfPart) end;
      			["GET get-info-rooms"] = function (event) return wrap_async_run(event,get_info_rooms) end;
		};
	});
end

but “/get-info-rooms” and “/nbConfPart-info” is not working …!
"/get-info-rooms" always return “{}” @ledahu is urs is working fine?
and “/nbConfPart” returns 500 Internal Server Error and I think I have the same as @ledahu where it says the roomname is null, in the console log :

error
jero_web_service_1      | 192.168.0.118 - - [27/Mar/2020:09:36:04 +0600] "GET /nbConfPart-info HTTP/1.1" 500 447 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36"
jero_prosody_service_1  | runnerJSoqD3px                            error	Encountered error: /prosody-plugins/mod_muc_size.lua:201: attempt to index field 'jitsi_meet_room' (a nil value)
jero_prosody_service_1  | stack traceback:
jero_prosody_service_1  | 	/prosody-plugins/mod_muc_size.lua:201: in function 'handler'
jero_prosody_service_1  | 	/prosody-plugins/util.lib.lua:69: in function 'func'
jero_prosody_service_1  | 	/usr/lib/prosody/util/async.lua:127: in function </usr/lib/prosody/util/async.lua:125>
jero_prosody_service_1  | http.server                               error	Traceback[httpserver]: /usr/lib/prosody/util/async.lua:137: /prosody-plugins/mod_muc_size.lua:201: attempt to index field 'jitsi_meet_room' (a nil value)
jero_prosody_service_1  | stack traceback:
jero_prosody_service_1  | 	/prosody-plugins/mod_muc_size.lua:201: in function 'handler'
jero_prosody_service_1  | 	/prosody-plugins/util.lib.lua:69: in function 'func'
jero_prosody_service_1  | 	/usr/lib/prosody/util/async.lua:127: in function </usr/lib/prosody/util/async.lua:125>
jero_prosody_service_1  | stack traceback:
jero_prosody_service_1  | 	[C]: in function 'error'
jero_prosody_service_1  | 	/usr/lib/prosody/util/async.lua:137: in function 'handler'
jero_prosody_service_1  | 	/usr/lib/prosody/util/async.lua:211: in function 'run'
jero_prosody_service_1  | 	/prosody-plugins/util.lib.lua:80: in function </prosody-plugins/util.lib.lua:64>
jero_prosody_service_1  | 	(...tail calls...)
jero_prosody_service_1  | 	/usr/lib/prosody/util/events.lua:79: in function </usr/lib/prosody/util/events.lua:75>
jero_prosody_service_1  | 	(...tail calls...)
jero_prosody_service_1  | 	/usr/lib/prosody/net/http/server.lua:248: in function </usr/lib/prosody/net/http/server.lua:176>
jero_prosody_service_1  | 	[C]: in function 'xpcall'
jero_prosody_service_1  | 	/usr/lib/prosody/net/http/server.lua:108: in function 'process_next'
jero_prosody_service_1  | 	/usr/lib/prosody/net/http/server.lua:124: in function 'success_cb'
jero_prosody_service_1  | 	/usr/lib/prosody/net/http/parser.lua:177: in function 'feed'
jero_prosody_service_1  | 	/usr/lib/prosody/net/http/server.lua:155: in function </usr/lib/prosody/net/http/server.lua:154>
jero_prosody_service_1  | 	(...tail calls...)
jero_prosody_service_1  | 	/usr/lib/prosody/net/server_select.lua:915: in function </usr/lib/prosody/net/server_select.lua:899>
jero_prosody_service_1  | 	[C]: in function 'xpcall'
jero_prosody_service_1  | 	/usr/bin/prosody:80: in function 'loop'
jero_prosody_service_1  | 	/usr/bin/prosody:90: in main chunk
jero_prosody_service_1  | 	[C]: in ?

do u think the problem is in mod_muc_size module or other?
does nbConfPart-info and get-info-rooms need roomname parameters or something?
Thanx in advance :heartbeat:

Ah, you modifies original mod_muc_size.lua and want to add functions, right?
I uses original mod_muc_size, so I can’t help you.

But, I read your error log; I think your new functions are wrong.
I’ve searched forum and I found same issue, and the thread author seems already fixed it : How to get room name in prosody plugin?
Please try modification of How to get room name in prosody plugin? .

in your mod_muc_size module ,is there functions for /get-info-rooms and /nbConfpart ?

No. They are not official functions. See original one : https://github.com/jitsi/jitsi-meet/blob/master/resources/prosody-plugins/mod_muc_size.lua

oh yeah, I see… I downloaded this and then added that extra 2 functions discussed in this community… I badly need these functions as I wanna know about all current rooms in the server,not just specific room I know… Thanx for ur help and plz share if u find anything… The link u shared I didnt quite understand all what he did actually though

I created a new function which lists all room names on the server for you. New function, “handle_list_room” returns all of room names with JSON (array of string).
All of codes I posted here are licensed under same license as Jitsi Meet (Apache License 2.0), so you can use freely ( see https://github.com/jitsi/jitsi-meet/blob/master/LICENSE ).

Entire modified mod_muc_size.lua is below:

-- Prosody IM
-- Copyright (C) 2017 Atlassian
-- Modifed by jenus (2020/03/28, License is same as Jitsi meet, See: https://github.com/jitsi/jitsi-meet/blob/master/LICENSE)
--

local jid = require "util.jid";
local it = require "util.iterators";
local json = require "util.json";
local iterators = require "util.iterators";
local array = require"util.array";
local wrap_async_run = module:require "util".wrap_async_run;

local tostring = tostring;
local neturl = require "net.url";
local parse = neturl.parseQuery;

-- option to enable/disable room API token verifications
local enableTokenVerification
    = module:get_option_boolean("enable_roomsize_token_verification", false);

local token_util = module:require "token/util".new(module);
local get_room_from_jid = module:require "util".get_room_from_jid;

-- no token configuration but required
if token_util == nil and enableTokenVerification then
    log("error", "no token configuration but it is required");
    return;
end

-- required parameter for custom muc component prefix,
-- defaults to "conference"
local muc_domain_prefix
    = module:get_option_string("muc_mapper_domain_prefix", "conference");

local muc_component_host = module:get_option_string("muc_component");

--- Verifies room name, domain name with the values in the token
-- @param token the token we received
-- @param room_address the full room address jid
-- @return true if values are ok or false otherwise
function verify_token(token, room_address)
    if not enableTokenVerification then
        return true;
    end

    -- if enableTokenVerification is enabled and we do not have token
    -- stop here, cause the main virtual host can have guest access enabled
    -- (allowEmptyToken = true) and we will allow access to rooms info without
    -- a token
    if token == nil then
        log("warn", "no token provided");
        return false;
    end

    local session = {};
    session.auth_token = token;
    local verified, reason = token_util:process_and_verify_token(session);
    if not verified then
        log("warn", "not a valid token %s", tostring(reason));
        return false;
    end

    if not token_util:verify_room(session, room_address) then
        log("warn", "Token %s not allowed to join: %s",
            tostring(token), tostring(room_address));
        return false;
    end

    return true;
end

--- Handles request for retrieving the room size
-- @param event the http event, holds the request query
-- @return GET response, containing a json with participants count,
--         tha value is without counting the focus.
function handle_get_room_size(event)
    if (not event.request.url.query) then
        return 400;
    end

	local params = parse(event.request.url.query);
	local room_name = params["room"];
	local domain_name = params["domain"];
    local subdomain = params["subdomain"];

    local room_address
        = jid.join(room_name, muc_domain_prefix.."."..domain_name);

    if subdomain and subdomain ~= "" then
        room_address = "["..subdomain.."]"..room_address;
    end

    if not verify_token(params["token"], room_address) then
        return 403;
    end

	local room = get_room_from_jid(room_address);
	local participant_count = 0;

	log("debug", "Querying room %s", tostring(room_address));

	if room then
		local occupants = room._occupants;
		if occupants then
			participant_count = iterators.count(room:each_occupant());
		end
		log("debug",
            "there are %s occupants in room", tostring(participant_count));
	else
		log("debug", "no such room exists");
		return 404;
	end

	if participant_count > 1 then
		participant_count = participant_count - 1;
	end

	return [[{"participants":]]..participant_count..[[}]];
end

--- Handles request for retrieving the room participants details
-- @param event the http event, holds the request query
-- @return GET response, containing a json with participants details
function handle_get_room (event)
    if (not event.request.url.query) then
        return 400;
    end

	local params = parse(event.request.url.query);
	local room_name = params["room"];
	local domain_name = params["domain"];
    local subdomain = params["subdomain"];
    local room_address
        = jid.join(room_name, muc_domain_prefix.."."..domain_name);

    if subdomain ~= "" then
        room_address = "["..subdomain.."]"..room_address;
    end

    if not verify_token(params["token"], room_address) then
        return 403;
    end

	local room = get_room_from_jid(room_address);
	local participant_count = 0;
	local occupants_json = array();

	log("debug", "Querying room %s", tostring(room_address));

	if room then
		local occupants = room._occupants;
		if occupants then
			participant_count = iterators.count(room:each_occupant());
			for _, occupant in room:each_occupant() do
			    -- filter focus as we keep it as hidden participant
			    if string.sub(occupant.nick,-string.len("/focus"))~="/focus" then
				    for _, pr in occupant:each_session() do
					local nick = pr:get_child_text("nick", "http://jabber.org/protocol/nick") or "";
					local email = pr:get_child_text("email") or "";
					occupants_json:push({
					    jid = tostring(occupant.nick),
					    email = tostring(email),
					    display_name = tostring(nick)});
				    end
			    end
			end
		end
		log("debug",
            "there are %s occupants in room", tostring(participant_count));
	else
		log("debug", "no such room exists");
		return 404;
	end

	if participant_count > 1 then
		participant_count = participant_count - 1;
	end

	return json.encode(occupants_json);
end;

--- Handles request for retrieving the room lists
-- @param event the http event, holds the request query
-- @return GET response, containing a json with room lists
function handle_list_room(event)
    if muc_component_host == nil then
        return json.encode({})
    end
    local component = hosts[muc_component_host]
    local muc = component.modules.muc;
    local room_names = {}

    for room in muc.all_rooms() do
        table.insert(room_names, tostring(room:get_name()))
    end

    return json.encode(room_names)
end;

function module.load()
    module:depends("http");
	module:provides("http", {
		default_path = "/";
		route = {
			["GET room-size"] = function (event) return wrap_async_run(event,handle_get_room_size) end;
			["GET sessions"] = function () return tostring(it.count(it.keys(prosody.full_sessions))); end;
			["GET room"] = function (event) return wrap_async_run(event,handle_get_room) end;
			["GET room-list"] = function (event) return wrap_async_run(event,handle_list_room) end;
		};
	});
end

Patch of for mod_muc_size.lua is below (Optional):

--- raw.lua	2018-07-10 01:45:13.000000000 +0700
+++ mod_muc_size.lua	2020-03-28 15:29:58.852391727 +0700
@@ -31,6 +31,8 @@ end
 local muc_domain_prefix
     = module:get_option_string("muc_mapper_domain_prefix", "conference");
 
+local muc_component_host = module:get_option_string("muc_component");
+
 --- Verifies room name, domain name with the values in the token
 -- @param token the token we received
 -- @param room_address the full room address jid
@@ -176,6 +178,24 @@ function handle_get_room (event)
 	return json.encode(occupants_json);
 end;
 
+--- Handles request for retrieving the room lists
+-- @param event the http event, holds the request query
+-- @return GET response, containing a json with room lists
+function handle_list_room(event)
+    if muc_component_host == nil then
+        return json.encode({})
+    end
+    local component = hosts[muc_component_host]
+    local muc = component.modules.muc;
+    local room_names = {}
+
+    for room in muc.all_rooms() do
+        table.insert(room_names, tostring(room:get_name()))
+    end
+
+    return json.encode(room_names)
+end;
+
 function module.load()
     module:depends("http");
 	module:provides("http", {
@@ -184,6 +204,7 @@ function module.load()
 			["GET room-size"] = function (event) return wrap_async_run(event,handle_get_room_size) end;
 			["GET sessions"] = function () return tostring(it.count(it.keys(prosody.full_sessions))); end;
 			["GET room"] = function (event) return wrap_async_run(event,handle_get_room) end;
+			["GET room-list"] = function (event) return wrap_async_run(event,handle_list_room) end;
 		};
 	});
 end

After copy mod_muc_size.lua (or apply patch), you need to add below line into VirtualHost "meet.jitsi" section in prosody’s jitsi-meet.cfg.lua :

muc_component = "muc.meet.jitsi"

And add below lines to nginx’s meet.conf:

location = /room-list {
    proxy_pass http://xmpp.meet.jitsi:5280/room-list;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header Host meet.jitsi;
    add_header Content-Type "application/json; charset=UTF-8";
}

Then after restart, you can obtain all room info by API :

  1. Get rooms list from http://meet.example.com/room-list
  2. Get room info one by one from http://meet.example.com/room-info?room=OBTAINED_ROOM_NAME
1 Like

thanx a lot… I will give it a try :heart: