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
I get tis error when I try to start the phoenix application
** (Mix) Could not start application ejabberd: exited in: :ejabberd_app.start(:normal, [])
** (EXIT) {:aborted, {:no_exists, :passwd, :attributes}}
any ideas?
You are missing Mnesia tables.
Thanks . That fixed it . Btw is there an xmpp client within ejabberd? What was the replacement for exmpp ?
No, there is no XMPP client inside ejabberd.
Latest commits in ejabberd made the fix permanent so that you do not have that error anymore. Use ejabberd >= 16.01.0.
This is Great Wonderful information.. Awesome ideas Thanks..
Web Development India
Just jumping into this array of technologies – this was useful, so thanks :-)
Can I ask, architecturally, if i wanted to use eJabberd to provide a real time chat component to a web api I am writing using Phoenix, would I expose the websockets via at the Phoenix layer or go directly to eJabberd? I’m sure I could probably do both but as i’m just learning i’m not sure of the implications.
hey Steven, I really hope you solved this back in 2015 :) Currently tasing almost the same issue and some architectural advise would be really helpful! :) thank you!
Hi! Mickaël Rémond
I was impressed from this article.
I have used MngooseIM already and RoR so I wanted to make MIM + Phoenix to work together like this.
My first effort is at https://github.com/kevinblade/phoenix-mim.
I want to let me know about your thoughts of my app.
Thank you.
Just put your effort and contribute on original and more up to date ejabberd. That’s where the future is and we have more to come coming around Elixir :)
Is it possible to have same user credentials for ejabberd and phoenix web app, is there a plug-in for ejabbrd to authenticate against users in the web app.>
Yes, it is possible to have a module that share credentials, but we did not write such a module yet. You would have to code it yourself.
Hi Sir,
Thanks for the helpful post
But, I am getting error compiling the application using (mix do deps.get, compile)
Error is
** (Mix) Invalid requirement >= 17.07.0 for app ejabberd
Please help me to resolve this issue.
Thanks
iex -S mix phx.server
===> Compiling jiffy
‘.’ is not recognized as an internal or external command,
operable program or batch file.
===> Hook for compile failed!
** (Mix) Could not compile dependency :jiffy, “escript.exe “c:/Users/Shaun Chua/.mix/rebar3” bare compile –paths “c:/Users/Shaun Chua/hello/_build/dev/lib/*/ebin”” command failed. You can recompile this dependency with “mix deps.compile jiffy”, update it with “mix deps.update jiffy” or clean it with “mix deps.clean jiffy”
Hi! Thanks for this introduction to embedding ejabberd.
It looks like “deps/ejabberd/include/jlib.hrl” no longer exists in ejabberd ~> 19.8.
Is there another recommended record structure to do this jid-to-username conversion? Thanks!
I get the following error in Phoenix 1.7:
(RuntimeError) error parsing file deps/ejabberd/include/jlib.hrl, got: {:error, :enoent}
Stacktrace:
│ (elixir 1.14.4) lib/record/extractor.ex:84: Record.Extractor.read_file/2
│ (elixir 1.14.4) lib/record/extractor.ex:50: Record.Extractor.extract_record/2
│ lib/chat_web/controllers/ejabberd_controller.ex:5: (module)
I think a lot has changed. An updated tutorial to the most recent version of Elixir/Phoenix will be very hepful.
Thanks for a you do.