我对Erlang环境有点陌生
我正在编写一个电子邮件测试应用程序,该应用程序在主题交换中使用随机生成的routing_keys过滤传入的电子邮件,以使电子邮件进入系统
一旦它们在队列中交付(和处理),我想用先前随机的routing_key再次标记它们,以将它们路由到另一个交易所,以使它们为最终消耗做好准备。
第二个生产步骤给我带来了真正的麻烦
我正在从具有handle_info模式匹配的tcp套接字(由第三层程序:spamassassin处理)中获取数据
我依靠gen_server首先通过常规amqp_client / include / amqp_client.hrl库使用消息
我在gen_server行为中使用handle_info,然后对参数进行模式匹配。
检测传递的AMQP消息是通过handle_info回调中的函数头(记录)完成的
TCP套接字非常适合与spamassassin对话,它向我返回一个3元组,其中包含二进制字符串数据,如下所示:
{tcp,#Port<0.55>,<<"SPAMD/1.1 0 EX_OK\r\nContent-length: 564\r\nSpam: True ; 7.9 / 5.0\r\n\r\nReceived: from localhost by XXXX.ikexpress.com\n\twith SpamAssassin (version 3.4.2);\n\tThu, 15 Aug 2019 21:44:12 +0200\nX-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on\n\tXXXXX.ikexpress.com\nX-Spam-Flag: YES\nX-Spam-Level: *******\nX-Spam-Status: Yes, score=7.9 required=5.0 tests=EMPTY_MESSAGE,MISSING_DATE,\n\tMISSING_FROM,MISSING_HEADERS,MISSING_MID,MISSING_SUBJECT,\n\tNO_HEADERS_MESSAGE,NO_RECEIVED,NO_RELAYS autolearn=no\n\tautolearn_force=no version=3.4.2\nMIME-Version: 1.0\nContent-Type: multipart/mixed; boundary=\"----------=_5D55B60C.D2FC2670\"\n\n">>}
第二个handle_info中的循环匹配来自正在监听的gen_tcp服务器的答案,但我必须进行打包以将其发送到主题Exchange(topic_scored_email交换)
***My gen_server****
handle_info({#'basic.deliver'{routing_key=Key, consumer_tag=Tag}, Content}, State) ->
#amqp_msg{props = Properties, payload = Payload} = Content,
#'P_basic'{message_id = MessageId, headers = Headers} = Properties,
send_to_spamassassin:calcule_score(Payload),
{noreply, State};
handle_info(Msg, State) ->
case Msg of
{_,_,Data} ->
scored_email:main(Data);
{_,_} ->
end,
{noreply, State}.
***send_to_spamassassin function ***
calcule_score(Message) ->
case gen_tcp:connect("localhost", 783, [{mode, binary}]) of
{ok, Sock} ->
…
gen_tcp:send(Sock, Message2);
{error,_} ->
io:fwrite("Connection error! Quitting...~n")
end.
***scored_email***
main(Argv) ->
{ok, Connection} = amqp_connection:start(#amqp_params_network{virtual_host = <<"/">>}),
{ok, Channel} = amqp_connection:open_channel(Connection),
amqp_channel:call(Channel, #'exchange.declare'{exchange = <<"topic_scored_email">>,type = <<"topic">>}),
{RoutingKey, Message} = case Argv of
…
%DOING PATTERN MATCHING THAT WORKS HERE
…
end,
amqp_channel:cast(Channel,#'basic.publish'{exchange = <<"topic_scored_email">>,routing_key = RoutingKey},#amqp_msg{payload = Message})
第一个问题是数据的类型(二进制字符串),但我想使用BIF binary_to_tuple或类似的东西可能是一种解决方法。
我很难理解的是我如何传递正确的RoutingKey,因为Erlang具有功能,所以没有副作用或赋值。
对我来说,使用OTP抽象无法实现格式数据的更改(AMQP->原始TCP->然后是AMQP)
但是,我想重新组合每条经过处理的邮件,并使用正确的路由键匹配上面5行。
我该如何修改我的代码?我来自命令式语言,在这里达到了极限……
您的
答案 0 :(得分:1)
第一个问题是数据的类型(二进制字符串),但我想它可以 使用BIF binary_to_tuple或类似的东西可以解决此问题。
在所有语言中,您都必须弄清楚如何解析从套接字读取的数据。
我很难理解的是我如何才能通过正确的决定 RoutingKey,由于Erlang具有功能,因此没有副作用或 分配。
那是一条主线,但实际上,递归函数的参数变量可用于存储值。您可以将路由密钥存储在State
变量中,然后在所有gen_server回调函数中都可用。 State
可以是30个元素的元组,因此对State
变量中可以存储多少信息没有限制。
另一种选择是使用ets / dets表(即erlang数据库)来存储带有路由键的消息,直到您准备发送“所有内容”为止。进行其他处理。
{RoutingKey,消息} = ...
但是,我想用 正确的路由键匹配上面的5行。
如果您使用的是同一功能,是什么导致您无法使用变量RoutingKey
和Message
中的路由键和消息?我不清楚如果所有代码都在一个函数中怎么会有问题。我认为您可以执行以下操作:
{RoutingKey, Message} = ...
ProcessedMsg = process_this(Message)
{RoutingKey, ProcessedMsg}
我建议您发布一个简单的问题示例-避免所有复杂的匹配和amqp_channel内容将问题归结为问题的核心,例如
handle_info(Msg, State) ->
RoutingKey = 3,
ProcessedMsg = "hello",
%% Here, I want to write: ....