2010-01-06 85 views
13

我在写一个ejabberd模块来过滤数据包。我需要获取主机名来使用gen_mod:get_module_opt()来拉一些配置。如何在Erlang中创建全局变量

我有4个重要的功能:

  1. start(Host, _Opt):这是一个ejabberd函数加载我的模块。我在这里得到Host原子
  2. filter_packet({From, To, XML}):这是我的数据包过滤器挂钩。我无法将自定义参数传递给此函数,因为它是ejabberd中的钩子。
  3. get_translation(XmlData)filter_packet()在循环
  4. fetch_translation(XmlData)调用get_translation():从get_translation()递归调用。这是我打电话给gen_mod:get_module_opt(),因此需要Host

我的问题是,我怎么能采取Hoststart(),并把它放在一个全局变量,从而使fetch_translation可以访问它?

回答

9

“最简单的方法”是创建一个名为ets表,并将其放在那里。

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), 
    ... 

请注意,这是一个“通用”解决方案。 Ejabberd可能会提供你想要的设施,但我无法帮助你。

+0

THX捷思。 该模块编译好,但为'ets:new(my_table,[named_table,protected,set,{keypos,1}])给出'badarg'错误,' – Adil 2010-01-06 15:56:45

+0

如果'my_table'表存在,您将得到一个badarg 。您可能需要检查表是否已经存在,或者将它包装在try-catch块中 – Zed 2010-01-06 17:23:41

+0

除了上面给出的内容外,我没有在任何地方创建'my_table'。 – Adil 2010-01-07 08:59:25

1

您可以开始新的邮件过滤流程并使用erlang:register/2进行注册,然后路由所有filter_packet/1请求(潜在的瓶颈)。

-define(?SERVER, msg_filter). 

start(Host, Opt) -> 
    {ok, Pid} = spawn(?MODULE, filter_loop, [Host, Opt]), 
    register(?SERVER, Pid). 

filter_loop(Host, Opt) -> 
    receive 
     {Pid, filter_packet, {_From, _To, XML}} -> 
      Trans = get_translation(XML, Host), 
      Pid ! {?SERVER, translation, Trans}, 
      filter_loop(Host, Opt) 
    end. 

filter_packet(Pack) -> 
    ?SERVER ! {self(), filter_packet, Pack} 
    receive 
     {?SERVER, translation, Trans} -> 
      % wrap translation 
      UpdatedPacket 
    end. 
1

假设您正在过滤传入的数据包,那么To#jid.lserver可能是您的主机。

+0

嗨andi5。你能解释一下“To#jid.lserver”是什么意思。我如何设置/获取它? – Adil 2010-01-17 13:22:30

+0

这只是最好的猜测,但我想To是绑定到jid类型记录的变量(请参阅src/jlib.hrl中的记录定义,位于底部)。要#jid.lserver意味着您要访问记录的lserver字段,其中lserver是jid域的小写版本。如果您在shell中遇到问题,请运行rd(jid,{user,[...]})。 – andi5 2010-01-17 19:48:38

1

为你的描述猜测比你在单域部署ejabberd(没有虚拟主机),

哟可以使用?MYNAME宏观获得本地XMPP域(见定义ejabberd.hrl)。

9

这可能听起来有点矫枉过正,但你可能会考虑实现一个非常基本的gen_server。它包含一个可用于其回调的状态,并且数据可以保存在那里。对于你的情况,你可以写类似这样一个模块:

-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}. 
1

您定义的全局变量在你的模块顶部...像下面

-define (Your Variable, "your host name here"). 

如。

​​

并且您可以在模块中的所有方法中使用此全局变量。

io:fwrite("Global Value ~p", [?RelayHost]). 

-AjAy

+4

-define不定义变量。它定义了编译时常量。 – 2012-02-10 08:18:37

+0

那么如何定义全局变量呢?谢谢 – 2012-02-24 11:13:57

+0

不可能定义一个全局变量。 – 2012-02-28 09:24:58