aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMickaël Rémond <mremond@process-one.net>2015-01-29 18:43:47 +0100
committerMickaël Rémond <mremond@process-one.net>2015-02-10 17:56:44 +0100
commit01e1f677c72b923251f7021bc024319ff129d42d (patch)
tree38c3101d86f42b62774df909193cdfe6be69614c
parentDocument EJABBERD_CONFIG_PATH in ejabberdctl.cfg (diff)
Add Elixir support to ejabberd
Diffstat (limited to '')
-rw-r--r--.gitignore3
-rw-r--r--Makefile.in15
-rw-r--r--configure.ac15
-rwxr-xr-xejabberdctl.template105
-rw-r--r--lib/Ejabberd/hooks.ex13
-rw-r--r--lib/Ejabberd/logger.ex9
-rw-r--r--lib/ejabber.ex2
-rw-r--r--lib/mod_presence_demo.ex21
-rw-r--r--rebar.config.script12
-rw-r--r--src/ejabberd_config.erl63
-rw-r--r--vars.config.in1
11 files changed, 203 insertions, 56 deletions
diff --git a/.gitignore b/.gitignore
index d5b7862f1..c72fcdc36 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,3 +35,6 @@
/src/ejabberd.app.src
/src/eldap_filter_yecc.erl
/vars.config
+/dialyzer/
+/test/*.beam
+/logs/
diff --git a/Makefile.in b/Makefile.in
index 575b0bdc7..a9a16f04e 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -11,6 +11,9 @@ DESTDIR =
# /etc/ejabberd/
ETCDIR = $(DESTDIR)@sysconfdir@/ejabberd
+# /bin/
+BINDIR = $(DESTDIR)@bindir@
+
# /sbin/
SBINDIR = $(DESTDIR)@sbindir@
@@ -118,6 +121,7 @@ install: all
|| $(INSTALL) -b -m 640 $(G_USER) ejabberd.yml.example $(ETCDIR)/ejabberd.yml
$(SED) -e "s*{{rootdir}}*@prefix@*" \
-e "s*{{installuser}}*@INSTALLUSER@*" \
+ -e "s*{{bindir}}*@bindir@*" \
-e "s*{{libdir}}*@libdir@*" \
-e "s*{{sysconfdir}}*@sysconfdir@*" \
-e "s*{{localstatedir}}*@localstatedir@*" \
@@ -132,6 +136,11 @@ install: all
# Administration script
[ -d $(SBINDIR) ] || $(INSTALL) -d -m 755 $(SBINDIR)
$(INSTALL) -m 550 $(G_USER) ejabberdctl.example $(SBINDIR)/ejabberdctl
+ # Elixir binaries
+ [ -d $(BINDIR) ] || $(INSTALL) -d -m 755 $(BINDIR)
+ [ -f deps/elixir/bin/iex ] && $(INSTALL) -m 550 $(G_USER) deps/elixir/bin/iex $(BINDIR)/iex
+ [ -f deps/elixir/bin/elixir ] && $(INSTALL) -m 550 $(G_USER) deps/elixir/bin/elixir $(BINDIR)/elixir
+ [ -f deps/elixir/bin/mix ] && $(INSTALL) -m 550 $(G_USER) deps/elixir/bin/mix $(BINDIR)/mix
#
# Init script
$(SED) -e "s*@ctlscriptpath@*$(SBINDIR)*" \
@@ -145,6 +154,9 @@ install: all
$(INSTALL) -m 644 ebin/*.beam $(BEAMDIR)
$(INSTALL) -m 644 deps/*/ebin/*.app $(BEAMDIR)
$(INSTALL) -m 644 deps/*/ebin/*.beam $(BEAMDIR)
+ # Install Elixir and Elixir dependancies
+ -$(INSTALL) -m 644 deps/*/lib/*/ebin/*.app $(BEAMDIR)
+ -$(INSTALL) -m 644 deps/*/lib/*/ebin/*.beam $(BEAMDIR)
rm -f $(BEAMDIR)/configure.beam
#
# ejabberd header files
@@ -201,6 +213,9 @@ uninstall: uninstall-binary
uninstall-binary:
rm -f $(SBINDIR)/ejabberdctl
+ rm -f $(BINDIR)/iex
+ rm -f $(BINDIR)/elixir
+ rm -f $(BINDIR)/mix
rm -fr $(DOCDIR)
rm -f $(BEAMDIR)/*.beam
rm -f $(BEAMDIR)/*.app
diff --git a/configure.ac b/configure.ac
index ddbc48b88..8715c86ba 100644
--- a/configure.ac
+++ b/configure.ac
@@ -106,10 +106,10 @@ AC_ARG_ENABLE(mssql,
esac],[db_type=generic])
AC_ARG_ENABLE(all,
-[AC_HELP_STRING([--enable-all], [same as --enable-nif --enable-odbc --enable-mysql --enable-pgsql --enable-pam --enable-zlib --enable-riak --enable-json --enable-iconv --enable-debug --enable-lager --enable-tools (useful for Dialyzer checks, default: no)])],
+[AC_HELP_STRING([--enable-all], [same as --enable-nif --enable-odbc --enable-mysql --enable-pgsql --enable-pam --enable-zlib --enable-riak --enable-json --enable-elixir --enable-iconv --enable-debug --enable-lager --enable-tools (useful for Dialyzer checks, default: no)])],
[case "${enableval}" in
- yes) nif=true odbc=true mysql=true pgsql=true pam=true zlib=true riak=true json=true iconv=true debug=true lager=true tools=true ;;
- no) nif=false odbc=false mysql=false pgsql=false pam=false zlib=false riak=false json=false iconv=false debug=false lager=false tools=false ;;
+ yes) nif=true odbc=true mysql=true pgsql=true pam=true zlib=true riak=true json=true elixir=true iconv=true debug=true lager=true tools=true ;;
+ no) nif=false odbc=false mysql=false pgsql=false pam=false zlib=false riak=false json=false elixir=false iconv=false debug=false lager=false tools=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-all) ;;
esac],[])
@@ -185,6 +185,14 @@ AC_ARG_ENABLE(json,
*) AC_MSG_ERROR(bad value ${enableval} for --enable-json) ;;
esac],[if test "x$json" = "x"; then json=false; fi])
+AC_ARG_ENABLE(elixir,
+[AC_HELP_STRING([--enable-elixir], [enable Elixir support (default: no)])],
+[case "${enableval}" in
+ yes) elixir=true ;;
+ no) elixir=false ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-elixir) ;;
+esac],[if test "x$elixir" = "x"; then elixir=false; fi])
+
AC_ARG_ENABLE(iconv,
[AC_HELP_STRING([--enable-iconv], [enable iconv support (default: yes)])],
[case "${enableval}" in
@@ -240,6 +248,7 @@ AC_SUBST(pam)
AC_SUBST(zlib)
AC_SUBST(riak)
AC_SUBST(json)
+AC_SUBST(elixir)
AC_SUBST(iconv)
AC_SUBST(debug)
AC_SUBST(lager)
diff --git a/ejabberdctl.template b/ejabberdctl.template
index 4e8234c99..2025fd22d 100755
--- a/ejabberdctl.template
+++ b/ejabberdctl.template
@@ -12,6 +12,7 @@ ERLANG_NODE=ejabberd@localhost
# define default environment variables
SCRIPT_DIR=`cd ${0%/*} && pwd`
ERL={{erl}}
+IEX={{bindir}}/iex
INSTALLUSER={{installuser}}
# Compatibility in ZSH
@@ -128,6 +129,7 @@ if [ "$ERLANG_NODE" = "${ERLANG_NODE%.*}" ] ; then
else
NAME="-name"
fi
+IEXNAME="-$NAME"
# define ejabberd environment parameters
if [ "$EJABBERD_CONFIG_PATH" != "${EJABBERD_CONFIG_PATH%.yml}" ] ; then
@@ -183,6 +185,67 @@ start()
# attach to server
debug()
{
+ debugwarning
+ TTY=`tty | sed -e 's/.*\///g'`
+ $EXEC_CMD "$ERL \
+ $NAME debug-${TTY}-${ERLANG_NODE} \
+ -remsh $ERLANG_NODE \
+ -hidden \
+ $KERNEL_OPTS \
+ $ERLANG_OPTS $ARGS \"$@\""
+}
+
+# attach to server using Elixir
+iexdebug()
+{
+ debugwarning
+ TTY=`tty | sed -e 's/.*\///g'`
+ # Elixir shell is hidden as default
+ $EXEC_CMD "$IEX \
+ $IEXNAME debug-${TTY}-${ERLANG_NODE} \
+ --remsh $ERLANG_NODE \
+ --erl \"$KERNEL_OPTS\" \
+ --erl \"$ERLANG_OPTS\" --erl \"$ARGS\" --erl \"$@\""
+}
+
+# start interactive server
+live()
+{
+ livewarning
+ $EXEC_CMD "$ERL \
+ $NAME $ERLANG_NODE \
+ -pa $EJABBERD_EBIN_PATH \
+ -mnesia dir \"\\\"$SPOOL_DIR\\\"\" \
+ $KERNEL_OPTS \
+ $EJABBERD_OPTS \
+ -s ejabberd \
+ $ERLANG_OPTS $ARGS \"$@\""
+}
+
+# start interactive server with Elixir
+iexlive()
+{
+ livewarning
+ $EXEC_CMD "$IEX \
+ $IEXNAME $ERLANG_NODE \
+ -pa $EJABBERD_EBIN_PATH \
+ --erl \"-mnesia dir \\\"$SPOOL_DIR\\\"\" \
+ --erl \"$KERNEL_OPTS\" \
+ --erl \"$EJABBERD_OPTS\" \
+ --app ejabberd \
+ --erl \"$ERLANG_OPTS\" --erl $ARGS --erl \"$@\""
+}
+
+etop()
+{
+ $EXEC_CMD "$ERL \
+ $NAME debug-${TTY}-${ERLANG_NODE} \
+ -hidden -s etop -s erlang halt -output text -node $ERLANG_NODE"
+}
+
+# TODO: refactor debug warning and livewarning
+debugwarning()
+{
if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then
echo "--------------------------------------------------------------------"
echo ""
@@ -199,21 +262,13 @@ debug()
echo "--------------------------------------------------------------------"
echo "To bypass permanently this warning, add to ejabberdctl.cfg the line:"
echo " EJABBERD_BYPASS_WARNINGS=true"
- echo "Press any key to continue"
+ echo "Press return to continue"
read foo
echo ""
- fi
- TTY=`tty | sed -e 's/.*\///g'`
- $EXEC_CMD "$ERL \
- $NAME debug-${TTY}-${ERLANG_NODE} \
- -remsh $ERLANG_NODE \
- -hidden \
- $KERNEL_OPTS \
- $ERLANG_OPTS $ARGS \"$@\""
+ fi
}
-# start interactive server
-live()
+livewarning()
{
check_start
if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then
@@ -231,34 +286,22 @@ live()
echo "--------------------------------------------------------------------"
echo "To bypass permanently this warning, add to ejabberdctl.cfg the line:"
echo " EJABBERD_BYPASS_WARNINGS=true"
- echo "Press any key to continue"
+ echo "Press return to continue"
read foo
echo ""
fi
- $EXEC_CMD "$ERL \
- $NAME $ERLANG_NODE \
- -pa $EJABBERD_EBIN_PATH \
- -mnesia dir \"\\\"$SPOOL_DIR\\\"\" \
- $KERNEL_OPTS \
- $EJABBERD_OPTS \
- -s ejabberd \
- $ERLANG_OPTS $ARGS \"$@\""
-}
-
-etop()
-{
- $EXEC_CMD "$ERL \
- $NAME debug-${TTY}-${ERLANG_NODE} \
- -hidden -s etop -s erlang halt -output text -node $ERLANG_NODE"
}
+# TODO: Make iex command display only if ejabberd Elixir support has been enabled
help()
{
echo ""
echo "Commands to start an ejabberd node:"
- echo " start Start an ejabberd node in server mode"
- echo " debug Attach an interactive Erlang shell to a running ejabberd node"
- echo " live Start an ejabberd node in live (interactive) mode"
+ echo " start Start an ejabberd node in server mode"
+ echo " debug Attach an interactive Erlang shell to a running ejabberd node"
+ echo " iexdebug Attach an interactive Elixir shell to a running ejabberd node"
+ echo " live Start an ejabberd node in live (interactive) mode"
+ echo " iexlive Start an ejabberd node in live (interactive) mode, within an Elixir shell"
echo ""
echo "Optional parameters when starting an ejabberd node:"
echo " --config-dir dir Config ejabberd: $ETC_DIR"
@@ -409,7 +452,9 @@ wait_for_status()
case $ARGS in
' start') start;;
' debug') debug;;
+ ' iexdebug') iexdebug;;
' live') live;;
+ ' iexlive') iexlive;;
' etop') etop;;
' started') wait_for_status 0 30 2;; # wait 30x2s before timeout
' stopped') wait_for_status 3 15 2 && stop_epmd;; # wait 15x2s before timeout
diff --git a/lib/Ejabberd/hooks.ex b/lib/Ejabberd/hooks.ex
new file mode 100644
index 000000000..a9e0dfef7
--- /dev/null
+++ b/lib/Ejabberd/hooks.ex
@@ -0,0 +1,13 @@
+defmodule Ejabberd.Hooks do
+
+ # Generic hook setting features
+ def add(hook_name, host, module, function, priority) do
+ :ejabberd_hooks.add(hook_name, host, module, function, priority)
+ end
+
+ # Should be named 'removed'
+ def delete(hook_name, host, module, function, priority) do
+ :ejabberd_hooks.delete(hook_name, host, module, function, priority)
+ end
+
+end
diff --git a/lib/Ejabberd/logger.ex b/lib/Ejabberd/logger.ex
new file mode 100644
index 000000000..bef1cb3aa
--- /dev/null
+++ b/lib/Ejabberd/logger.ex
@@ -0,0 +1,9 @@
+defmodule Ejabberd.Logger do
+
+ def critical(message, args \\ []), do: :lager.log(:critical, [], message, args)
+ def error(message, args \\ []), do: :lager.log(:error, [], message, args)
+ def warning(message, args \\ []), do: :lager.log(:warning, [], message, args)
+ def info(message, args \\ []), do: :lager.log(:info, [], message, args)
+ def debug(message, args \\ []), do: :lager.log(:debug, [], message, args)
+
+end
diff --git a/lib/ejabber.ex b/lib/ejabber.ex
new file mode 100644
index 000000000..a843abc97
--- /dev/null
+++ b/lib/ejabber.ex
@@ -0,0 +1,2 @@
+defmodule Ejabberd do
+end
diff --git a/lib/mod_presence_demo.ex b/lib/mod_presence_demo.ex
new file mode 100644
index 000000000..89fc60d87
--- /dev/null
+++ b/lib/mod_presence_demo.ex
@@ -0,0 +1,21 @@
+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
diff --git a/rebar.config.script b/rebar.config.script
index 30d479eab..64398f33e 100644
--- a/rebar.config.script
+++ b/rebar.config.script
@@ -95,6 +95,9 @@ CfgDeps = lists:flatmap(
{tag, "1.4.2"}}}];
({json, true}) ->
[{jiffy, ".*", {git, "git://github.com/davisp/jiffy"}}];
+ ({elixir, true}) ->
+ [{rebar_elixir_plugin, ".*", {git, "git://github.com/yrashk/rebar_elixir_plugin"}},
+ {elixir, "1.1.*", {git, "git://github.com/elixir-lang/elixir"}}];
({iconv, true}) ->
[{p1_iconv, ".*", {git, "git://github.com/processone/eiconv"}}];
({lager, true}) ->
@@ -142,6 +145,13 @@ CfgXrefs = lists:flatmap(
[]
end, Cfg),
+ElixirConfig = case lists:keysearch(elixir, 1, Cfg) of
+ {value, {elixir, true}} ->
+ [{plugins, [rebar_elixir_compiler, rebar_exunit] },
+ {lib_dirs, ["deps/elixir/lib"]}];
+ _ ->
+ []
+ end,
{ok, Cwd} = file:get_cwd(),
@@ -157,7 +167,7 @@ Config = [{erl_opts, Macros ++ HiPE ++ DebugInfo ++
[{"(XC - UC) || (XU - X - B - "
++ string:join(CfgXrefs, " - ") ++ ")", []}]},
{post_hooks, PostHooks ++ CfgPostHooks},
- {deps, Deps ++ CfgDeps}],
+ {deps, Deps ++ CfgDeps}] ++ ElixirConfig,
%%io:format("ejabberd configuration:~n ~p~n", [Config]),
Config.
diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl
index cacec8bf1..54a635905 100644
--- a/src/ejabberd_config.erl
+++ b/src/ejabberd_config.erl
@@ -707,26 +707,40 @@ replace_module(mod_roster_odbc) -> {mod_roster, odbc};
replace_module(mod_shared_roster_odbc) -> {mod_shared_roster, odbc};
replace_module(mod_vcard_odbc) -> {mod_vcard, odbc};
replace_module(mod_vcard_xupdate_odbc) -> {mod_vcard_xupdate, odbc};
-replace_module(Module) -> Module.
-
-replace_modules(Modules) ->
- lists:map(
- fun({Module, Opts}) ->
- case replace_module(Module) of
- {NewModule, DBType} ->
- emit_deprecation_warning(Module, NewModule, DBType),
- NewOpts = [{db_type, DBType} |
- lists:keydelete(db_type, 1, Opts)],
- {NewModule, transform_module_options(Module, NewOpts)};
- NewModule ->
- if Module /= NewModule ->
- emit_deprecation_warning(Module, NewModule);
- true ->
- ok
- end,
- {NewModule, transform_module_options(Module, Opts)}
- end
- end, Modules).
+replace_module(Module) ->
+ case is_elixir_module(Module) of
+ true -> expand_elixir_module(Module);
+ false -> Module
+ end.
+
+replace_modules(Modules) -> lists:map( fun({Module, Opts}) -> case
+ replace_module(Module) of {NewModule, DBType} ->
+ emit_deprecation_warning(Module, NewModule, DBType), NewOpts =
+ [{db_type, DBType} | lists:keydelete(db_type, 1, Opts)],
+ {NewModule, transform_module_options(Module, NewOpts)}; NewModule
+ -> if Module /= NewModule -> emit_deprecation_warning(Module,
+ NewModule); true -> ok end, {NewModule,
+ transform_module_options(Module, Opts)} end end, Modules).
+
+%% Elixir module naming
+%% ====================
+
+%% If module name start with uppercase letter, this is an Elixir module:
+is_elixir_module(Module) ->
+ case atom_to_list(Module) of
+ [H|_] when H >= 65, H =< 90 -> true;
+ _ ->false
+ end.
+
+%% We assume we know this is an elixir module
+expand_elixir_module(Module) ->
+ case atom_to_list(Module) of
+ %% Module name already specified as an Elixir from Erlang module name
+ "Elixir." ++ _ -> Module;
+ %% if start with uppercase letter, this is an Elixir module: Append 'Elixir.' to module name.
+ ModuleString ->
+ list_to_atom("Elixir." ++ ModuleString)
+ end.
strings_to_binary([]) ->
[];
@@ -1009,5 +1023,10 @@ emit_deprecation_warning(Module, NewModule, DBType) ->
" instead", [Module, NewModule, DBType]).
emit_deprecation_warning(Module, NewModule) ->
- ?WARNING_MSG("Module ~s is deprecated, use ~s instead",
- [Module, NewModule]).
+ case is_elixir_module(NewModule) of
+ %% Do not emit deprecation warning for Elixir
+ true -> ok;
+ false ->
+ ?WARNING_MSG("Module ~s is deprecated, use ~s instead",
+ [Module, NewModule])
+ end.
diff --git a/vars.config.in b/vars.config.in
index dce8cd204..7621d1390 100644
--- a/vars.config.in
+++ b/vars.config.in
@@ -26,6 +26,7 @@
{zlib, @zlib@}.
{riak, @riak@}.
{json, @json@}.
+{elixir, @elixir@}.
{lager, @lager@}.
{iconv, @iconv@}.