Welcome – Prosody IM
Prosody is a Jabber/XMPP server written in Lua

Prosody is an Open Source XMPP communication server for commercial messaging and chat providers. With prosody, it is easy for the developers to rapidly develop added functionality or prototype new protocols with the extensibility and the flexibility that Prosody offers. Developers can link up a Prosody server with other Prosody servers, or any other implementation that is XMPP compatible.

What do Prosody do in the Jitsi System?

Jitsi mainly uses prosody to signal and manage presence between the connected users. As a Jitsi user, you cannot see that Prosody lies underneath and manages your presence with the other users but that is how and what is does. Prosody manages your online status, messaging content, display attributes, etc. in Jitsi.

Following architecture diagram shows where the Prosody component is located in the Jitsi architecture and which other components that the Prosody component connects to.

Jitsi Architecture

Even though Jitsi uses Prosody, the Prosody component is completely separate with the Jitsi component, such that we can make changes to the component for different uses. This gives the Jitsi developers high level of configurability that can enable a lot of custom features. Just like the one we are going to do in this article.

Prosody Plugins

Prosody has a plugins directory which contains all the optional modules that it uses. Plugins are only usable if they are enabled. There are number of default plugins, which can be found in the jitsi-meet project.

jitsi-meet/resources/prosody-plugins at master · jitsi/jitsi-meet
Jitsi Meet - Secure, Simple and Scalable Video Conferences that you use as a standalone app or embed in your web application. - jitsi-meet/resources/prosody-plugins at master · jitsi/jitsi-meet

This means these are also there in the Jitsi instance if you have installed Jitsi on a server. You have to install Prosody when installing a Jitsi instance. You will get a prosody config at /etc/prosody/conf.d/meet.domain.cfg.lua. There you can define the enabled modules.

modules_enabled = {
	"bosh";
	"http";
	"pubsub";
	...
}

This array of modules will be loaded every time the Prosody service starts. (If you do a change to the config files you have restart the service to apply changes.) This is how you enable an optional module for Prosody.

Note that some of the plugins require extra configuration changes.

Plugin Paths

In the config you can see an option called plugin_paths = { "/usr/share/jitsi-meet/prosody-plugins/" }. This is where the default Prosody plugins for Jitsi are located. You can add new paths which contain your plugins, or place your new plugins in the default path.

lua Programming Language

The Programming Language Lua
Official web site of the Lua language

Prosody plugins are written in lua language which is why we can see plugin files in .lua extension. It is a language which they identify as a powerful, efficient, lightweight, embeddable scripting language. Prosody plugins have less number of lines and descriptive syntax because of the lua usage.

How to Activate an existing Prosody Plugin?

We'll activate the Prosody plugin mod_muc_size.lua and try use that plugin here.

  1. First we need to enable the module in the Prosody configuration.
modules_enabled = {
	"bosh";
	"http";
	"pubsub";
	...
	"muc_size";
}
We don't use the mod_ prefix here.

2.  Restart the Prosody service to take the changes into effect.

service prosody restart

3.  According to the plugin definition, we can call the /room API endpoint to get data. We can access the API endpoint in the following way.

https://meet.domain.com/room?room=room_name

But this will end up returning a 404 Not Found code. This is coming from the nginx service at the server. The reason for this code is that the Prosody service that we are looking for is running locally in the server, such that it is not discoverable in the public domain of the server.

4.  We have to introduce a rule at the nginx level to direct the request to the Prosody service if any request comes to the /room URL.

location = /room {
	proxy_pass http://127.0.0.1:5280/room?$args&domain=meet.domain.com;
	proxy_set_header X-Forwarded-For $remote_addr;
	proxy_set_header Host meet.domain.com;
	add_header Content-Type "application/json; charset=UTF-8";
	add_header 'Access-Control-Allow-Origin' '*';
}

5.  Restart the nginx service for the reverse proxy changes to take effect.

service nginx restart

6.  Now we can see the desired output sent from the Prosody service.

[
	{"display_name":"Michael","email":"michael@gmail.com","jid":"room_name@conference.meet.domain.com/f9a6340f"},
	{"display_name":"Lyon","email":"lyon@gmail.com","jid":"room_name@conference.meet.domain.com/eb20392d"}
]

Like this you can make use of all the Prosody modules provided by Jitsi.

Write Your Own Prosody Plugin with http Module

Now we'll update the plugin logic and deploy as a new plugin. Assume that we need some extra information about the room and in a different url. For this we need to change the output format a little bit.

  1. We'll first change the API URL from the routes section.
function module.load()
    module:depends("http");
	module:provides("http", {
		default_path = "/";
		route = {
			["GET api/room_data"] = function (event) return async_handler_wrapper(event, handle_get_room_data) end;
		};
	});
end

2.  We need to change the content of the API handler to match our needs.

if room then
		local occupants = room._occupants;

		if occupants then
			participant_count = iterators.count(room:each_occupant());
			for _, occupant in room:each_occupant() do
			    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

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

        response = {
            success = true;
            room = {
                room_name = room_name;
                room_address = room_address;
                participants_count = participant_count;
                participants = occupants_json;
            }
        };
	else
		response = {
            success = false;
            message = "No room found"
        };
	end

	return { status_code = 200; body = json.encode(response); };

We can take the same function from the mod_muc_size.lua plugin and changed it to match our required output.

3.  Since we have to add this as a new plugin create a new .lua file inside your Prosody plugin_paths directory. For this we'll create a new file called mod_muc_room_data.lua.

4.  To load this plugin file, we need to load it under the Prosody configuration file.

modules_enabled = {
	"bosh";
	"http";
	"pubsub";
	...
	"muc_size";
	"muc_room_data";
}

5. We have to restart Prosody for the changes to take effect. Once you restart, the new module will also load. If you use any additional modules inside your module, those modules also need to be included here.

6.  Still when accessed outside the domain, this API endpoint is not discoverable. We can add another reverse proxy entry in the nginx config and make the API accessible to the outside.

location = /api/room_data {
	proxy_pass http://127.0.0.1:5280/api/room_data?$args&domain=meet.domain.com;
	proxy_set_header X-Forwarded-For $remote_addr;
	proxy_set_header Host meet.domain.com;
	add_header Content-Type "application/json; charset=UTF-8";
	add_header 'Access-Control-Allow-Origin' '*';
}

This is only required since we are adding a plugin based on the "http" module. Different use cases might not need this step to be completed.

7.  Restart the nginx service to apply the changes.

8.  Access the API at your newly created Prosody plugin as https://meet.domain.com/api/room_data?room=room_name


You can play more with Prosody and Jitsi by understanding more about the Jitsi ecosystem. And you can also contribute to the community with what you do.

Also learn .lua to write great scripts. You can not only create API endpoints, you can even modify data, attach listeners, etc. by unveiling the data layer at the Prosody level. You can even find out great Prosody plugins written by the developers in the community.