如何在 Erlang 中创建全局变量

发布于 2024-08-17 03:48:36 字数 694 浏览 6 评论 0原文

我正在编写一个 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

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

谁的新欢旧爱 2024-08-24 03:48:36

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

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.

給妳壹絲溫柔 2024-08-24 03:48:36

这听起来可能有些过分,但您可以考虑实现一个非常基本的 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}.

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}.
末蓝 2024-08-24 03:48:36

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

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

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

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

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

-阿杰

You define your global variable on your module top...like below

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

eg.

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

and you can use this Global variable in all your method in your module.

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

-AjAy

桜花祭 2024-08-24 03:48:36

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

Try use 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)

三生一梦 2024-08-24 03:48:36

您可以启动一个新的消息过滤进程并使用 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.

You could start a new message filtering process and register it using erlang:register/2, then route all filter_packet/1 requests through it (a potential bottleneck).

-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.
许一世地老天荒 2024-08-24 03:48:36

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

Say you are filtering incoming packets, then To#jid.lserver might be your host.

梨涡少年 2024-08-24 03:48:36

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

您可以使用 ?MYNAME 宏获取本地 XMPP 域(有关定义,请参阅 ejabberd.hrl)。

guessing for your description than you are in a single-domain ejabberd deployment (no virtual hosts),

yo can get the local XMPP domain using the ?MYNAME macro (see ejabberd.hrl for the definition).

要走干脆点 2024-08-24 03:48:36

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

You cannot create global variable but you can define a record outside your functions and create an instance of that record with properties then pass it down to the methods you call. Therefore, you can only share one record via method parameter.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文