Ejabberd module can't be found

67 Views Asked by At
-module(mod_mess_filter).
-behaviour(gen_mod).
%% Required by ?INFO_MSG macros
-include("logger.hrl").
   
%% Required by ?T macro
-include("translate.hrl").
-include_lib("xmpp/include/xmpp.hrl").
%% gen_mod API callbacks
-export([start/2, stop/1, depends/2, mod_options/1, mod_doc/0]).
-export([on_filter_packet/1]).
start(_Host, _Opts) ->
   ?INFO_MSG("Hello, my filter plugin!", []),
   ejabberd_hooks:add(filter_packet, global, ?MODULE, on_filter_packet, 0). 
on_filter_packet(Packet) -> 
   From = xmpp:get_from(Packet),
   To = xmpp:get_to(Packet),
   Type = xmpp:get_type(Packet),
   Content = post_request(From,To,Type,Packet),
   ?INFO_MSG("Mess : ~p", [Packet#message.body]),
   modify_packet(Packet, Content).
stop(_Host) ->
   ?INFO_MSG("Bye bye, ejabberd world!", []),
   ok.
depends(_Host, _Opts) ->
  [].
mod_options(_Host) ->
  [].
mod_doc() ->
   #{desc =>
         ?T("This is an example module.")}.
start_httpc() ->
 application:start(inets).
post_request(From, To, Type, Packet)
 when (Type == chat) orelse (Type == groupchat) ->
   BodyText = xmpp:get_text(Packet#message.body),
       ?INFO_MSG("From : ~p", [From]),
       ?INFO_MSG("To : ~p", [To]),
       ?INFO_MSG("Type : ~p", [Type]),
       ?INFO_MSG("BodyText : ~p", [BodyText]),
 start_httpc(),
 Options = [],
 Url = "https://123.249.79.79/xyapp/service/mess/filter",
 Headers = [
  {"Content-Type", "application/json"}
],
 UnicodeContent = BodyText,
 UnicodeFrom = jid:encode(From),
 UnicodeTo = jid:encode(To),
 Body = "{" 
           ++ "\"from\":" ++ "\"" ++ binary_to_list(UnicodeFrom) ++ "\","
           ++ "\"content\":" ++ "\"" ++ binary_to_list(UnicodeContent) ++ "\","
           ++ "\"to\":" ++ "\"" ++ binary_to_list(UnicodeTo) ++ "\"" ++
         "}",
{ok, Response} = httpc:request(post, {Url, Headers, "application/json", Body},Options, []),
 case Response of
  {{_, 200, _}, _, RstBody} ->
     ?INFO_MSG("RstBody: ~p", [RstBody]),        
     RstBody;
  {error, _} ->
     BodyText
 end;
post_request(_From, _To, _Type, _Packet) ->
   ok.
modify_packet(Packet, Content) ->
   Packet#message{body = [#text{data = Content}]}.

Is my path :

root@debianPT001:~/.ejabberd-modules/sources/mod_mess_filter/src# ls

mod_mess_filter.erl

root@debianPT001:~/.ejabberd-modules/sources/mod_mess_filter/src# pwd
/root/.ejabberd-modules/sources/mod_mess_filter/src

root@debianPT001:~/.ejabberd-modules/sources/mod_mess_filter# ls mod_mess_filter.spec src

I hope to implement a module for filtering user chat content, which will put the processed string returned after my request into the packet for essay collection

I am currently performing the same operation as in the official document

But I found that ejabberctl couldn't find the plugins I configured into it

3

There are 3 best solutions below

1
Badlop On

If my path : root/.ejabberd-modules/sources/mod_mess_filter/mod_mess_filter.erl

I guess you are following https://docs.ejabberd.im/developer/extending-ejabberd/modules/#add-your-module

First of all, something very important that isn't mentioned in that page: do NOT run ejabberdctl module_update_specs, because that will delete the existing modules and your source code!

In step 2 you forgot that the *.erl file must be inside src/ directory, it should be: root/.ejabberd-modules/sources/mod_mess_filter/src/mod_mess_filter.erl

A trick to enable the module easily: add the file root/.ejabberd-modules/sources/mod_mess_filter/conf/mod_mess_filter.yml with this content:

modules:
  mod_mess_filter: {}

Once you do those changes, you can install it with "ejabberdctl module_install mod_mess_filter", and the module will start, but it is not compatible with recent ejabberd versions. I try your source code with ejabberd 23.10 and crashes.

I've made minor changes to use xmpp library, filter only chat/groupchat messages, and send only the body text:

-module(mod_mess_filter).

-behaviour(gen_mod).

%% Required by ?INFO_MSG macros
-include("logger.hrl").

%% Required by ?T macro
-include("translate.hrl").

-include_lib("xmpp/include/xmpp.hrl").

%% gen_mod API callbacks
-export([start/2, stop/1, depends/2, mod_options/1, mod_doc/0]).

-export([on_filter_packet/1]).

start(_Host, _Opts) ->
    ?INFO_MSG("Hello, my filter plugin!", []),
    ejabberd_hooks:add(filter_packet, global, ?MODULE, on_filter_packet, 0). 

on_filter_packet(Packet) -> 
    From = xmpp:get_from(Packet),
    To = xmpp:get_to(Packet),
    Type = xmpp:get_type(Packet),
    post_request(From,To,Type,Packet),
    Packet.

stop(_Host) ->
    ?INFO_MSG("Bye bye, ejabberd world!", []),
    ok.

depends(_Host, _Opts) ->
    [].

mod_options(_Host) ->
    [].

mod_doc() ->
    #{desc =>
          ?T("This is an example module.")}.

start_httpc() ->
  application:start(inets).

post_request(From, To, Type, Packet)
  when (Type == chat) orelse (Type == groupchat) ->
    BodyText = xmpp:get_text(Packet#message.body),
        ?INFO_MSG("From : ~p", [From]),
        ?INFO_MSG("To : ~p", [To]),
        ?INFO_MSG("Type : ~p", [Type]),
        ?INFO_MSG("BodyText : ~p", [BodyText]),
  start_httpc(),
  Options = [],
  Url = "http://123.249.79.79/xyapp/service/mess/filter",
  Headers = [
    {"Content-Type", "application/json"}
  ],
  UnicodeContent = BodyText,
  UnicodeFrom = jid:encode(From),
  UnicodeTo = jid:encode(To),
  Body = "{" 
            ++ "\"from\":" ++ "\"" ++ binary_to_list(UnicodeFrom) ++ "\","
            ++ "\"content\":" ++ "\"" ++ binary_to_list(UnicodeContent) ++ "\","
            ++ "\"to\":" ++ "\"" ++ binary_to_list(UnicodeTo) ++ "\"" ++
          "}",
  {ok, Response} = httpc:request(post, {Url, Headers, "application/json", Body},Options, []),
  case Response of
    {{_, 200, _}, _, RstBody} ->
      RstBody;
    {error, Cause} ->
      Cause
  end;
post_request(_From, _To, _Type, _Packet) ->
    ok.
4
Badlop On

Does ejabberd store and read modules from the path /root/.ejabberd-modules/? Or maybe ejabberd is using a different path?

One method to know the path that ejabberd is using for those modules:

ejabberdctl debug
ext_mod:modules_dir().

"/home/badlop/.ejabberd-modules"

Another method is to run ejabberdctl modules_update_specs, and search in the $HOME of the user that runs ejabberd the directory .ejabberd-modules.

0
Badlop On

I tried your new module source code with ejabberd 24.02 and my Jabber client, and it produced some error messages.

I've fixed those errors, and now it works for me:

  • when destination is online, the messages are sent correctly to him
  • when destination is offline, messages are stored in the offline strage database
  • when user becomes online again, the offline messages are sent to him
  • if any message is modified by the HTTP service, the modified message is sent to the online user, or is stored offline and delivered when he logins.

Here is the updated source code:

-module(mod_mess_filter).
-behaviour(gen_mod).
%% Required by ?INFO_MSG macros
-include("logger.hrl").
   
%% Required by ?T macro
-include("translate.hrl").
-include_lib("xmpp/include/xmpp.hrl").
%% gen_mod API callbacks
-export([start/2, stop/1, depends/2, mod_options/1, mod_doc/0]).
-export([on_filter_packet/1]).
start(_Host, _Opts) ->
   ?INFO_MSG("Hello, my filter plugin!", []),
   ejabberd_hooks:add(filter_packet, global, ?MODULE, on_filter_packet, 0). 
on_filter_packet(Packet) -> 
   From = xmpp:get_from(Packet),
   To = xmpp:get_to(Packet),
   Type = xmpp:get_type(Packet),
   post_request(From,To,Type,Packet).
stop(_Host) ->
   ?INFO_MSG("Bye bye, ejabberd world!", []),
   ok.
depends(_Host, _Opts) ->
  [].
mod_options(_Host) ->
  [].
mod_doc() ->
   #{desc =>
         ?T("This is an example module.")}.
start_httpc() ->
 application:start(inets).
post_request(From, To, Type, Packet)
 when (Type == chat) orelse (Type == groupchat) ->
   BodyText = xmpp:get_text(Packet#message.body),
       ?INFO_MSG("From : ~p", [From]),
       ?INFO_MSG("To : ~p", [To]),
       ?INFO_MSG("Type : ~p", [Type]),
       ?INFO_MSG("BodyText : ~p", [BodyText]),
 start_httpc(),
 Options = [],
 Url = "https://123.249.79.79/xyapp/service/mess/filter",
 Headers = [
  {"Content-Type", "application/json"}
],
 UnicodeContent = BodyText,
 UnicodeFrom = jid:encode(From),
 UnicodeTo = jid:encode(To),
 Body = "{" 
           ++ "\"from\":" ++ "\"" ++ binary_to_list(UnicodeFrom) ++ "\","
           ++ "\"content\":" ++ "\"" ++ binary_to_list(UnicodeContent) ++ "\","
           ++ "\"to\":" ++ "\"" ++ binary_to_list(UnicodeTo) ++ "\"" ++
         "}",
{ok, Response} = httpc:request(post, {Url, Headers, "application/json", Body},Options, []),
 Content = case Response of
  {{_, 200, _}, _, RstBody} ->
     ?INFO_MSG("RstBody: ~p", [RstBody]),        
     RstBody;
  {error, _} ->
     BodyText
 end,
 modify_packet(Packet, Content);
post_request(_From, _To, _Type, Packet) ->
   Packet.
modify_packet(Packet, Content) ->
   Packet#message{body = [#text{data = Content}]}.