16

我正在编写一个 ejabberd 模块来过滤数据包。我需要获取主机名以使用gen_mod:get_module_opt().

我有 4 个重要功能:

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

我的问题是,如何Host从全局变量中获取start()并将其放入全局变量中,以便fetch_translation可以访问它?

4

8 回答 8

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}.
于 2011-05-19T13:06:48.827 回答
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 可能会为您提供所需的设施,但我无法帮助您。

于 2010-01-06T15:31:42.567 回答
2

您在模块顶部定义全局变量...如下所示

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

例如。

-define (RelayHost, "smtp.gmail.com").

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

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

-阿杰

于 2012-02-09T10:56:55.713 回答
1

猜测您的描述,而不是单域 ejabberd 部署(无虚拟主机),

您可以使用 ?MYNAME 宏获取本地 XMPP 域(参见 ejabberd.hrl 的定义)。

于 2010-02-01T19:05:21.247 回答
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.
于 2010-01-13T17:08:07.147 回答
1

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

于 2010-01-17T09:05:52.673 回答
1

尝试使用persistent_term

1> persistent_term:put(hello, <<"world">>).
ok
2> persistent_term:get(hello).       
<<"world">>
3> persistent_term:erase(hello).
true
4> persistent_term:get(hello).  
** exception error: bad argument
     in function  persistent_term:get/1
        called as persistent_term:get(hello)

于 2021-04-22T21:30:58.837 回答
0

您不能创建全局变量,但可以在函数之外定义记录并使用属性创建该记录的实例,然后将其传递给您调用的方法。因此,您只能通过方法参数共享一条记录。

于 2021-04-22T13:35:01.253 回答