2017-01-25 6 views
0

У меня есть установка Ejabberd 17.01, где мне нужно нажать уведомление, если получатель находится в автономном режиме. Это, по-видимому, общая задача, и решения, использующие настраиваемый модуль Ejabberd, можно найти повсюду. Однако я просто не понимаю. Во-первых, вот мне сценарий:Ejabberd: ошибка в простом модуле для обработки сообщений в автономном режиме

-module(mod_offline_push). 
    -behaviour(gen_mod). 

    -export([start/2, stop/1]). 
    -export([push_message/3]). 

    -include("ejabberd.hrl"). 
    -include("logger.hrl"). 
    -include("jlib.hrl"). 

    start(Host, _Opts) -> 
      ?INFO_MSG("mod_offline_push loading", []), 
      ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, push_message, 10), 
      ok. 

    stop(Host) -> 
      ?INFO_MSG("mod_offline_push stopping", []), 
      ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, push_message, 10), 
      ok. 

    push_message(From, To, Packet) -> 
      ?INFO_MSG("mod_offline_push -> push_message", [To]), 
      Type = fxml:get_tag_attr_s(<<"type">>, Packet), % Supposedly since 16.04 
      %Type = xml:get_tag_attr_s(<<"type">>, Packet), % Supposedly since 13.XX 
      %Type = xml:get_tag_attr_s("type", Packet), 
      %Type = xml:get_tag_attr_s(list_to_binary("type"), Packet), 
      ?INFO_MSG("mod_offline_push -> push_message", []), 
      ok. 

Проблема заключается линия Type = ... линии в методе push_message; без этой строки регистрируется последнее информационное сообщение (так что крючок определенно работает). При просмотре в Интернете я могу найти все виды вызовов функций для извлечения элементов из Packet. Насколько я понимаю, со временем это изменилось с новыми выпусками. Но это нехорошо, все варианты приводят к какой-то ошибке. В настоящее время способ возвращается:

2017-01-25 20:38:08.701 [error] <0.21678.0>@ejabberd_hooks:run1:332 {function_clause,[{fxml,get_tag_attr_s,[<<"type">>,{message,<<>>,normal,<<>>,{jid,<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>,<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>},{jid,<<"carl">>,<<"xxx.xxx.xxx.xxx">>,<<>>,<<"carl">>,<<"xxx.xxx.xxx.xxx">>,<<>>},[],[{text,<<>>,<<"sfsdfsdf">>}],undefined,[],#{}}],[{file,"src/fxml.erl"},{line,169}]},{mod_offline_push,push_message,3,[{file,"mod_offline_push.erl"},{line,33}]},{ejabberd_hooks,safe_apply,3,[{file,"src/ejabberd_hooks.erl"},{line,382}]},{ejabberd_hooks,run1,3,[{file,"src/ejabberd_hooks.erl"},{line,329}]},{ejabberd_sm,route,3,[{file,"src/ejabberd_sm.erl"},{line,126}]},{ejabberd_local,route,3,[{file,"src/ejabberd_local.erl"},{line,110}]},{ejabberd_router,route,3,[{file,"src/ejabberd_router.erl"},{line,87}]},{ejabberd_c2s,check_privacy_route,5,[{file,"src/ejabberd_c2s.erl"},{line,1886}]}]} 

running hook: {offline_message_hook,[{jid,<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>,<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>},{jid,<<"carl">>,<<"xxx.xxx.xxx.xxx">>,<<>>,<<"carl">>,<<"xxx.xxx.xxx.xxx">>,<<>>},{message,<<>>,normal,<<>>,{jid,<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>,<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>},{jid,<<"carl">>,<<"xxx.xxx.xxx.xxx">>,<<>>,<<"carl">>,<<"xxx.xxx.xxx.xxx">>,<<>>},[],[{text,<<>>,<<"sfsdfsdf">>}],undefined,[],#{}}]} 

Я новый Ejabberd и Erlang, так что я не могу интерпретировать эту ошибку, но линия 33, как указано в {mod_offline_push,push_message,3,[{file,"mod_offline_push.erl"}, {line,33}]}, безусловно, линия вызова get_tag_attr_s.

ОБНОВЛЕНИЕ 2017/01/27: Поскольку это стоило мне много головной боли - и я все еще не совсем счастлив - я размещаю здесь свой текущий рабочий модуль в надежде, что он может помочь другим. Моя настройка Ejabberd 17.01 работает на Ubuntu 16.04. Большинство вещей я попробовал и потерпел неудачу с, кажется, для более старых версий Ejabberd:

-module(mod_fcm_fork). 
-behaviour(gen_mod). 

%% public methods for this module 
-export([start/2, stop/1]). 
-export([push_notification/3]). 

%% included for writing to ejabberd log file 
-include("ejabberd.hrl"). 
-include("logger.hrl"). 
-include("xmpp_codec.hrl"). 

%% Copied this record definition from jlib.hrl 
%% Including "xmpp_codec.hrl" and "jlib.hrl" resulted in errors ("XYZ already defined") 
-record(jid, {user = <<"">> :: binary(), 
       server = <<"">> :: binary(), 
       resource = <<"">> :: binary(), 
       luser = <<"">> :: binary(), 
       lserver = <<"">> :: binary(), 
       lresource = <<"">> :: binary()}). 


start(Host, _Opts) -> 
    ?INFO_MSG("mod_fcm_fork loading", []), 
    % Providing the most basic API to the clients and servers that are part of the Inets application 
    inets:start(), 
    % Add hook to handle message to user who are offline 
    ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, push_notification, 10), 
    ok. 


stop(Host) -> 
    ?INFO_MSG("mod_fcm_fork stopping", []), 
    ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, push_notification, 10), 
    ok. 


push_notification(From, To, Packet) -> 
    % Generate JID of sender and receiver 
    FromJid = lists:concat([binary_to_list(From#jid.user), "@", binary_to_list(From#jid.server), "/", binary_to_list(From#jid.resource)]), 
    ToJid = lists:concat([binary_to_list(To#jid.user), "@", binary_to_list(To#jid.server), "/", binary_to_list(To#jid.resource)]), 
    % Get message body 
    MessageBody = Packet#message.body, 
    % Check of MessageBody is not empty 
    case MessageBody/=[] of 
     true -> 
      % Get first element (no idea when this list can have more elements) 
      [First | _ ] = MessageBody, 
      % Get message data and convert to string 
      MessageBodyText = binary_to_list(First#text.data), 
      send_post_request(FromJid, ToJid, MessageBodyText); 
     false -> 
      ?INFO_MSG("mod_fcm_fork -> push_notification: MessageBody is empty",[]) 
    end,  
    ok. 


send_post_request(FromJid, ToJid, MessageBodyText) -> 
    %?INFO_MSG("mod_fcm_fork -> send_post_request -> MessageBodyText = ~p", [Demo]),  
    Method = post, 
    PostURL = gen_mod:get_module_opt(global, ?MODULE, post_url,fun(X) -> X end, all), 
    % Add data as query string. Not nice, query body would be preferable 
    % Problem: message body itself can be in a JSON string, and I couldn't figure out the correct encoding. 
    URL = lists:concat([binary_to_list(PostURL), "?", "fromjid=", FromJid,"&tojid=", ToJid,"&body=", edoc_lib:escape_uri(MessageBodyText)]), 
    Header = [], 
    ContentType = "application/json", 
    Body = [], 
    ?INFO_MSG("mod_fcm_fork -> send_post_request -> URL = ~p", [URL]),  
    % ADD SSL CONFIG BELOW! 
    %HTTPOptions = [{ssl,[{versions, ['tlsv1.2']}]}], 
    HTTPOptions = [], 
    Options = [], 
    httpc:request(Method, {URL, Header, ContentType, Body}, HTTPOptions, Options), 
    ok. 

ответ

1

На самом деле он не со вторым арг Packet вы передаете FXML: get_tag_attr_s в функции push_message

{message,<<>>,normal,<<>>, 
     {jid,<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>, 
       <<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>}, 
     {jid,<<"carl">>,<<"xxx.xxx.xxx.xxx">>,<<>>,<<"carl">>, 
       <<"xxx.xxx.xxx.xxx">>,<<>>}, 
     [], 
     [{text,<<>>,<<"sfsdfsdf">>}], 
     undefined,[],#{}} 

, потому что он не xmlel

Похоже, что запись «сообщение» определено в инструменты/xmpp_codec. HRL с < < >> ид и типа 'нормальный'

xmpp_codec.hrl 
    -record(message, {id :: binary(), 
         type = normal :: 'chat' | 'error' | 'groupchat' | 'headline' | 'normal', 
         lang :: binary(), 
         from :: any(), 
         to :: any(), 
         subject = [] :: [#text{}], 
         body = [] :: [#text{}], 
         thread :: binary(), 
         error :: #error{}, 
         sub_els = [] :: [any()]}). 

I NCLUDE этот файл и использовать только

Type = Packet#message.type 

или, если вы ожидаете, двоичное значение

Type = erlang:atom_to_binary(Packet#message.type, utf8) 
+0

Отлично, спасибо! Я слишком много от новичков, чтобы понять смысл сообщений об ошибках. Я предполагаю, что эти изменения приходят с последней версией Ejabberd? Потому что даже результаты поиска в конце прошлого года используют способы, которые я пробовал. – Christian

+0

Я не знаю, может быть, последняя версия, я использую 14.07 –

+0

Помимо 'Packet', как я могу обрабатывать' From' и 'To'? Такие вещи, как 'To # jid.luser' бросают ошибки. Это работает только в том случае, если я включаю также 'jlib.hrl', но он, похоже, сталкивается с 'xmpp_codec.hrl'. – Christian

1

Новейший способ сделать это, кажется, чтобы быть с xmpp:get_type/1:

Type = xmpp:get_type(Packet), 

Он возвращает атом, в этом случае normal ,

+0

Спасибо, это работает, как хорошо! – Christian

+0

В качестве дополнительного вопроса: Как получить «тело» сейчас. Он не работает с 'xmpp: get_body (Packet)', который, как я думал, должен соответствовать https://www.process-one.net/docs/exmpp/devdoc/trunk/exmpp_message.html#get_body-1 – Christian

+0

'Body = Packet # message.body' или, если вам нужен текст: 'xmpp: get_text (Packet # message.body)' – user2610053