Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create global variables in Erlang

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 :

  1. start(Host, _Opt) : This is an ejabberd function to load my module. I get the Host atom here
  2. filter_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.
  3. get_translation(XmlData): filter_packet() calls get_translation() in a loop
  4. fetch_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?

like image 464
Adil Avatar asked Jan 06 '10 15:01

Adil


People also ask

How do I declare a variable in Erlang?

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.

What type of variables are used in Erlang?

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.


2 Answers

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}.
like image 21
Martin Dimitrov Avatar answered Oct 29 '22 04:10

Martin Dimitrov


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.

like image 149
Zed Avatar answered Oct 29 '22 04:10

Zed