I am writing an ejabberd module to filter packets. I need to get the hostname to pull some configs using gen_mod:get_module_opt()
.
I have 4 important functions :
start(Host, _Opt)
: This is an ejabberd function to load my module. I get the Host
atom herefilter_packet({From, To, XML})
: This is my packet filter hook. I cannot pass custom params to this function, as it is a hook in ejabberd.get_translation(XmlData)
: filter_packet()
calls get_translation()
in a loopfetch_translation(XmlData)
: called recursively from get_translation()
. This is where I am calling gen_mod:get_module_opt()
, and hence need the Host
.My question is, how can I take Host
from start()
and put it in a global variable, so that fetch_translation
can access it?
In Erlang, all the variables are bound with the '=' statement. All variables need to start with the upper case character. In other programming languages, the '=' sign is used for the assignment, but not in the case of Erlang. As stated, variables are defined with the use of the '=' statement.
Variables can contain alphanumeric characters, underscore and @. Variables are bound to values using pattern matching. Erlang uses single assignment, that is, a variable can only be bound once. The anonymous variable is denoted by underscore (_) and can be used when a variable is required but its value can be ignored.
It may sound as an overkill but you may consider implementing a very basic gen_server. It contains a state that is available to its callbacks and the data can be kept there. For your case you can write a module similar to this one:
-module(your_module_name).
-behaviour(gen_server).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-export([start/2, filter_loop/1]).
start(Host, Opt) ->
%% start the named gen server
gen_server:start({local, ?MODULE}, ?MODULE, Host, []).
filter_packet({From, To, XML}) ->
%% do your thing
gen_server:call(?MODULE, {fetch_translation, XmlData}).
%% this will be called by gen_server:start - just pass the Host
init(Host) ->
{ok, Host}.
handle_call({fetch_translation, XmlData}, _From, Host) ->
%% do your thing
{reply, ok, Host}.
%% you can ignore the rest - they are needed to be present
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
The "easiest way" is to create a named ets table, and put it in there.
start(Host, _Opt) ->
ets:new(my_table, [named_table, protected, set, {keypos, 1}]),
ets:insert(my_table, {host, Host}),
...
fetch_translation(XmlData) ->
[{_, Host}] = ets:lookup(my_table, host),
...
Note that this is a "general" solution. Ejabberd might provide facilities for what you want, but I cannot help you with that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With