Embedding ejabberd into an Elixir Phoenix Web application
By combining Elixir powerful web framework with ejabberd realtime messaging platform, you can build extremely powerful applications. This tutorial will help you get started.
Here is the screencast showing the whole process. Please read further for detailed step-by-step description and code.
Create a Phoenix application
The first step is to create your Phoenix application as usual.
First, you need to install Elixir 1.0.2+.
From there you can clone and build Phoenix framework:
prompt> git clone https://github.com/phoenixframework/phoenix.git && cd phoenix && git checkout v0.10.0 && mix do deps.get, compile
Finally, you can generate your Phoenix application template:prompt> mix phoenix.new /Users/mremond/demo/my_app
Please refer to Phoenix web site to learn more about it: Getting started with Phoenix.
Add ejabberd as a dependency for your application
You have two simple changes to perfom in your application mix.exs
initial file:
- Add ejabberd as a dependency for your application:
...
defp deps do
[{:phoenix, "~> 0.10.0"},
{:phoenix_ecto, "~> 0.1"},
{:postgrex, ">= 0.0.0"},
{:cowboy, "~> 1.0"},
{:ejabberd, ">= 15.03.0", github: "processone/ejabberd"}]
end
...
- Tell
mix
to start ejabberd when you launch your application:
...
def application do
[mod: {Phoenixtest, []},
applications: [:phoenix, :cowboy, :logger, :ejabberd]]
end
...
- Download and build all dependencies:
prompt> mix do deps.get, compile
For reference, here is the complete mix.exs
Before you can start your application, you need to configure ejabberd.
Configure your application and ejabberd
Copy ejabberd.yml
example file in application config/
directory. I put that file in a gist online to make that step easier:prompt> (cd config; wget https://gist.githubusercontent.com/mremond/383666d563025e86adfe/raw/723dfa50c955c112777f3361b4f2067b76a55d7b/ejabberd.yml)
You can tweak ejabberd config file to adapt it to your needs. Please, refer to ejabberd operation guide to configure it properly.
You also need to configure your Elixir application to tell it how to set global ejabberd values like configuration file, log directory and Mnesia file directory. In the file config/config.exs
, add specification ejabberd configuration for integration in your application:
...
config :ejabberd,
file: "config/ejabberd.yml",
log_path: 'logs/ejabberd.log'
# Customize Mnesia directory:
config :mnesia,
dir: 'mnesiadb/'
...
Make sure the directory where to place ejabberd log file does exist. If this is not the case, it will not be automatically created and no log file will be generated.
prompt> mkdir logs
Start your application
You can now start your application:
prompt> iex -S mix phoenix.server
As you see from the log printout, ejabberd is started along with your Elixir app.
You can create a user by entering the following command from Elixir command line:
iex(1)> :ejabberd_auth.try_register("mickael", "localhost", "mypass")
{:atomic, :ok}
You can connect with those credential from an XMPP client.
You can also connect on Elixir web server on https://localhost:4000/
Creating a page displaying ejabberd information
Let’s get started writing a Phoenix basic page that display ejabberd information.
In your project, edit the file web/router.ex
and add a reference to a /ejabberd
page in the my_app
scope:
get "/ejabberd", EjabberdController, :index
The scope “/” block of our router.ex
file should now look like this.
scope "/", MyApp do
pipe_through :browser # Use the default browser stack
get "/", PageController, :index
get "/ejabberd", EjabberdController, :index
end
Let’s then create the file web/controllers/ejabberd_controller.ex
:
defmodule MyApp.EjabberdController do
use MyApp.Web, :controller
# This is used to import the jid record structure from ejabberd:
require Record
Record.defrecord :jid, Record.extract(:jid, from: "deps/ejabberd/include/jlib.hrl")
plug :action
def index(conn, _params) do
# get online jid, parse and extract the user part.
online_users = :ejabberd_sm.connected_users
|> Enum.map &(jid(:jlib.string_to_jid(&1), :user))
render conn, "index.html", users: online_users
end
end
The code doing the heavy duty job the one getting online user by JID and extracting the username. This is a couple of lines of code:
# get online jid, parse and extract the user part.
online_users = :ejabberd_sm.connected_users
|> Enum.map &(jid(:jlib.string_to_jid(&1), :user))
We do not need anything fancy in our Phoenix view module and we will use default view placeholder web/views/ejabberd_view.ex
:
defmodule MyApp.EjabberdView do
use MyApp.Web, :view
end
Note: I could have put some data conversion code in the view code, but as the code is short, I preferred to have all the relevant ejabberd related code in one place.
Finally, we need the template for the page, named web/templates/ejabberd/index.html.eex
:
<div class="jumbotron">
<h2>Hello World, ejabberd meets Phoenix !</h2>
<h3>Here is the list of online users:</h3>
<%= for user <- @users do %>
<p><%= user %></p>
<% end %>
</div>
After starting the Phoenix server (iex -S mix phoenix.server
) and connecting to the server using your XMPP client, you should see a page like the following:
Conclusion
Here you are. This is all for this tutorial. You should now have environment properly set to start developing amazing ejabberd and XMPP powered web applications.
As you have seen, in a matter of minutes, you were able to create a powerful web app integrating ejabberd XMPP framework. By merging Phoenix and ejabberd, a whole new set of applications can emerge. We are eager to see what amazing apps you will build with it.
Special thanks to Sonny Scroggin (@scrogson) for the discussion and inspiration for this tutorial and video :)
References
- Gist containing all pieces of code: embed ejabberd in Elixir gist
- ejabberd website
- ejabberd github
- Elixir website
- Phoenix Framework