ejabberd joins the Elixir revolution

ejabberd has always been a key project for Erlang.

When I talk to many of the developers that have learned Erlang in that past 10 years, they often thank us for ejabberd. “ejabberd is the main reason why I have learned Erlang”.

That said, Erlang is not for everyone. Some people hate the syntax and cannot overcome their relunctance to learn it.

We already made the life of ejabberd users easier by providing YAML syntax for configuration files. YAML format is quite well know and avoided the typical mistakes make by users when editing “Erlang
tuple-atoms-and-list” syntax file. So, YAML configuration files format was received as a relief by many users.

Today, we are getting further and are making Elixir language a first class citizen for ejabberd. You can now develop any module you want in ejabberd leveraging all ejabberd API using only Elixir language.

For those who already know about Elixir, I already hear the excitement that this new feature is generating. I know, I am extremely excited myself. This change is probably the most important change in the life of ejabberd and we are already working with Elixir developer to improve on this existing implementation and boost our development community by making ejabberd development more accessible.

In turn, we are hoping to do for Elixir, what ejabberd did for Erlang in terms of recognition. For those who do not know about Elixir: This is a clean, modern programming language, created by Jose Valim, supported by hundreds of enthousiastic developers. It is inspired by Ruby syntax, with all the benefit of Erlang VM, that is clustering, lightweight processes, robustness, fault tolerance, etc.

If you do not yet know Elixir, you now have the best reason of the world to learn it :)

ejabberd_elixir

How to get started

Here is how to start using Elixir in ejabberd today. The change are available in ejabberd master branch and will be integrated in next ejabberd official version.

Prerequisite

Install Erlang R17

git clone and build ejabberd with Elixir support

$ git clone git@github.com:processone/ejabberd.git
$ cd ejabberd
$ chmod +x autogen.sh
$ ./autogen.sh 
$ ./configure --prefix=$HOME/my-ejabberd --enable-elixir
$ make && make install

Your ejabberd is now Elixir-enabled:

$ cd $HOME/my-ejabberd/
$ ./sbin/ejabberdctl live

(ejabberd@localhost)1> m('Elixir.Enum'). 
Module 'Elixir.Enum' compiled: Date: January 24 2015, Time: 16.27
Compiler options:  [debug_info]
Object file: /Users/mremond/my-ejabberd/lib/ejabberd/ebin/Elixir.Enum.beam
...

ejabberdctl module has now extra options:
– iexlive: Start ejabberd and keep an Elixir command open
– iexdebug: Attach and Elixir console to an already running ejabberd

It means you can use ejabberd shell using Elixir interactive commands:

$ cd $HOME/my-ejabberd/
$ ./sbin/ejabberdctl iexlive
...
iex(ejabberd@localhost)1> IO.puts "Hi ejabberd + elixir"
Hi ejabberd + elixir
:ok
...
# Creating a user:
iex(ejabberd@localhost)3> :ejabberd_auth.try_register("test2", "localhost", "mypass")
{:atomic, :ok}

Welcome to the revolution !

Writing ejabberd plugins in Elixir

You can now write plugins in Elixir and register hooks to expand ejabberd features in Elixir.

ejabberd lib directory is the place where you put your Elixir file so that the build chain knows how to compile them.

In ejabberd lib/ directory, add the file mod_presence_demo.ex:

defmodule ModPresenceDemo do
  @behaviour :gen_mod

  def start(_host, _opts) do
    :ok
  end

  def stop(_host) do
    :ok
  end
end

This is the smallest possible ejabberd module. We ignore the host and
the options for now.

When you type make your module should build properly.

When doing make install, it should install properly the newly created
module.

You can now use it in ejabberd configuration file ejabberd.yml. Just
add this line in the module section:

modules:
...
  ModPresenceDemo: {}

As you see, you can directly use the Elixir module name. ejabberd can
detect this is an Elixir module and use it appropriately.

Let’s expand a bit on this module:

defmodule ModPresenceDemo do
  import Ejabberd.Logger # this allow using info, error, etc for logging
  @behaviour :gen_mod

  def start(host, _opts) do
    info('Starting ejabberd module Presence Demo')
    Ejabberd.Hooks.add(:set_presence_hook, host, __ENV__.module, :on_presence, 50)
    :ok
  end

  def stop(host) do
    info('Stopping ejabberd module Presence Demo')
    Ejabberd.Hooks.delete(:set_presence_hook, host, __ENV__.module, :on_presence, 50)
    :ok
  end

  def on_presence(user, _server, _resource, _packet) do
    info('Receive presence for #{user}')
    :none
  end 
end

When you launch ejabberd with that new module, you should see the following line in the log file (or console if running live):

15:17:58.913 [info] Starting ejabberd module Presence Demo test

And anytime an XMPP client changes its presence, you should see the following in the log file:

15:30:01.266 [info] Receive presence for test

We are in the process of revamping our developer documentation to help both Erlang and Elixir developer get up to speed on ejabberd module development. You can expect follow up articles how how to get further
developing ejabberd with the power of Elixir.

In the meantime, all the ejabberd community is very glad to help get your started with ejabberd development using Elixir.

Please, join ejabberd mailing list or join the ejabberd chat room on XMPP (ejabberd@conference.jabber.ru)

We are all eager to see what great ejabberd extension you are going to build with Elixir.

12 thoughts on “ejabberd joins the Elixir revolution

  1. “We already made the life of ejabberd users easier by providing YAML syntax for configuration files.” – very funny because ejabberd developers don’t know how to use YAML in some situations (check issues on git hub).

  2. Hi, I’m following instructions and when I run ./sbin/ejabberdctl live it works fine, but when I run ./sbin/ejabberdctl iexlive i get:

    Erlang/OTP 18 [erts-7.1] [source-2882b0c] [64-bit] [async-threads:10] [hipe] [kernel-poll:false]

    10:50:54.969 [error] Supervisor ‘Elixir.Logger.Supervisor’ had child undefined started with ‘Elixir.Logger.Watcher’:watcher(error_logger,r.Logger.ErrorHandler’, {true,false,500}, link) at exit with reason normal in context child_terminated
    10:50:55.237 [info] Application lager started on node ejabberd@localhost
    10:50:55.255 [info] Application sasl started on node ejabberd@localhost
    10:50:55.265 [info] Application asn1 started on node ejabberd@localhost
    10:50:55.266 [info] Application public_key started on node ejabberd@localhost
    10:50:55.281 [info] Application ssl started on node ejabberd@localhost
    10:50:55.285 [info] Application p1_yaml started on node ejabberd@localhost
    10:50:55.294 [info] Application p1_tls started on node ejabberd@localhost
    10:50:55.298 [info] Application p1_xml started on node ejabberd@localhost
    10:50:55.301 [info] Application p1_stringprep started on node ejabberd@localhost
    10:50:55.304 [info] Application p1_zlib started on node ejabberd@localhost
    10:50:55.306 [info] Application p1_cache_tab started on node ejabberd@localhost
    10:50:55.523 [info] Application mnesia started on node ejabberd@localhost
    10:50:55.951 [info] Application inets started on node ejabberd@localhost
    10:50:56.266 [info] FQDN used to check DIGEST-MD5 SASL authentication: sandbox
    10:50:56.267 [info] Application oauth2 started on node ejabberd@localhost
    10:50:56.279 [info] Application p1_iconv started on node ejabberd@localhost
    10:50:56.302 [info] Reusing listening port for {5222,{0,0,0,0},tcp}
    10:50:56.302 [info] Reusing listening port for {5269,{0,0,0,0},tcp}
    10:50:56.302 [info] Reusing listening port for {5280,{0,0,0,0},tcp}
    10:50:56.302 [info] ejabberd 15.10.29 is started in the node ejabberd@localhost
    -mnesia dir “/root/my-ejabberd/var/lib/ejabberd” : Unknown option

Leave a Comment