如何在Erlang中创建全局变量

okxuctiv  于 2022-12-08  发布在  Erlang
关注(0)|答案(8)|浏览(278)

我正在写一个ejabberd模块来过滤数据包。我需要得到主机名来使用gen_mod:get_module_opt()拉一些配置。
我有4个重要职能:

  1. start(Host, _Opt):这是一个ejabberd函数,用于加载我的模块。
  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
    我的问题是,如何从start()中取出Host并将其放入全局变量中,以便fetch_translation可以访问它?
svgewumm

svgewumm1#

“最简单的方法”是创建一个命名的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可能会提供您想要的设施,但我无法帮助您。

jecbmhm3

jecbmhm32#

这听起来可能有点夸张,但你可以考虑实现一个非常基本的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}.
y0u0uwnf

y0u0uwnf3#

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

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

例如

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

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

io:fwrite("Global Value ~p", [?RelayHost]).
  • 阿贾伊
wfauudbj

wfauudbj4#

您可以启动一个新的消息筛选进程,并使用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.
5tmbdcev

5tmbdcev5#

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

oyjwcjzk

oyjwcjzk6#

而不是在单域ejabberd部署(没有虚拟主机)中,
可以使用?MYNAME宏获取本地XMPP域(有关定义,请参阅ejabberd.hrl)。

hsgswve4

hsgswve47#

尝试使用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)
um6iljoc

um6iljoc8#

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

相关问题