Can't compile a new module in ejabberd - erlang

I am trying to compile a new module for ejabberd in erlang.I am following this tutorial:http://jasonrowe.com/2011/12/30/ejabberd-offline-messages
I am trying to compile this code:
%% name of module must match file name
-module(mod_http_offline).
-author("Earl The Squirrel").
%% Every ejabberd module implements the gen_mod behavior
%% The gen_mod behavior requires two functions: start/2 and stop/1
-behaviour(gen_mod).
%% public methods for this module
-export([start/2, stop/1, create_message/3]).
%% included for writing to ejabberd log file
-include("ejabberd.hrl").
%% ejabberd functions for JID manipulation called jlib.
-include("jlib.hrl").
start(_Host, _Opt) ->
post_offline_message("testFrom", "testTo", "testBody"),
?INFO_MSG("mod_http_offline loading", []),
ejabberd_hooks:add(offline_message_hook, _Host, ?MODULE, create_message, 50).
stop (_Host) ->
?INFO_MSG("stopping mod_http_offline", []),
ejabberd_hooks:delete(offline_message_hook, _Host, ?MODULE, create_message, 50).
create_message(_From, _To, Packet) ->
Type = xml:get_tag_attr_s("type", Packet),
FromS = xml:get_tag_attr_s("from", Packet),
ToS = xml:get_tag_attr_s("to", Packet),
Body = xml:get_path_s(Packet, [{elem, "body"}, cdata]),
if (Type == "chat") ->
post_offline_message(FromS, ToS, Body)
end.
post_offline_message(From, To, Body) ->
?INFO_MSG("Posting From ~p To ~p Body ~p~n",[From, To, Body]),
?INFO_MSG("post request sent (not really yet)", []).
I have added jlib.hrl,ejabberd.hrl to my folder.But when I try to compile this code I am getting following errors:
jlib.hrl:22: can't find include lib "p1_xml/include/xml.hrl"
mod_http_offline.erl:21: undefined macro 'INFO_MSG/2'
mod_http_offline.erl:27: undefined macro 'INFO_MSG/2'
mod_http_offline.erl:44: undefined macro 'INFO_MSG/2'
jlib.hrl:426: record xmlel undefined
jlib.hrl:466: type xmlel() undefined
mod_http_offline.erl:11: function start/2 undefined
mod_http_offline.erl:11: function stop/1 undefined
mod_http_offline.erl:38: function post_offline_message/3 undefined
mod_http_offline.erl:8: Warning: behaviour gen_mod undefined
How can I resolve this ?
My Ejabberd version:2.1.11

The jlib.hrl file in ejabberd repository contains -include("ns.hrl"). (line 21) and -include_lib("p1_xml/include/xml.hrl"). line 22. The include_lib means that it will search the file in library path. You could modify this and add the necessary files in your directory (maybe a simple solution to test?) but I think that the clean way is to add tour file to the ejabberd application and use rebar to compile it.

Related

How to generate document for Ejabberd custom modules?

I have created some custom modules I need to create documentation for all my custom module So any help?
You can use edoc - http://erlang.org/doc/apps/edoc/chapter.html. Eg:
test_edoc.erl
-module(test_edoc).
-export([run/1]).
%% -------------------------------------------------------------------
%% #doc
%% Some description
%% #end
%% -------------------------------------------------------------------
-spec run(N :: integer()) -> Result :: integer() | error.
run(N) when is_integer(N) -> N + 1;
run(_) -> error.
Then in Erlang shell:
1> edoc:files(["test_edoc.erl"], [{dir, doc}]).
ok
Then in current folder where you run edoc:files/2 should be generated the doc folder, so, go to the doc folder and open in browser test_edoc.html

YAWs embedded with appmod not working for me

Alright, what am I doing wrong here. I'm trying the simple example of embedded YAWs from http://yaws.hyber.org/embed.yaws but with an appmod. I've added the my_app.erl file and compiled it. It works if not in embedded YAWs so I think it is specific to embedded.
-module(ybed).
-compile(export_all).
start() ->
{ok, spawn(?MODULE, run, [])}.
run() ->
Id = "embedded",
GconfList = [{ebin_dir, ["/Users/someuser/yawsembedded/ebin"]}],
Docroot = "/Users/someuser/yawstest",
SconfList = [{port, 8888},
{listen, {0,0,0,0}},
{docroot, Docroot},
{appmods, [{"/", my_app}]}
],
{ok, SCList, GC, ChildSpecs} =
yaws_api:embedded_start_conf(Docroot, SconfList, GconfList),
[supervisor:start_child(ybed_sup, Ch) || Ch <- ChildSpecs],
yaws_api:setconf(GC, SCList),
{ok, self()}.
Getting this Error:
ERROR erlang code threw an uncaught exception:
File: appmod:0
Class: error
Exception: undef
Req: {http_request,'GET',{abs_path,"/demo"},{1,1}}
Stack: [{my_app,out,
[{arg,#Port<0.2721>,
{{127,0,0,1},63720},
{headers,"keep-alive",
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"0.0.0.0:8888",undefined,undefined,undefined,undefined,
undefined,undefined,undefined,
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:40.0) Gecko/20100101 Firefox/40.0",
undefined,[],undefined,undefined,undefined,undefined,
undefined,undefined,undefined,undefined,
[{http_header,0,"Dnt",undefined,"1"},
{http_header,10,'Accept-Encoding',undefined,
"gzip, deflate"},
{http_header,11,'Accept-Language',undefined,"null"}]},
{http_request,'GET',{abs_path,"/demo"},{1,1}},
{http_request,'GET',{abs_path,"/demo"},{1,1}},
undefined,"/demo",undefined,undefined,
"/Users/someuser/yawstest","/",
"/Users/someuser/yawstest/demo",undefined,undefined,
<0.63.0>,[],"/","/",undefined}],
[]},
{yaws_server,deliver_dyn_part,8,
[{file,"yaws_server.erl"},{line,2818}]},
{yaws_server,aloop,4,[{file,"yaws_server.erl"},{line,1232}]},
{yaws_server,acceptor0,2,[{file,"yaws_server.erl"},{line,1068}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,239}]}]
The stack trace shows that your my_app:out/1 function is getting called, but you're getting an undef exception. This is occurring because the runtime can't find the my_app:out/1 function, which means either it can't find the module or the module exists but does not export an out/1 function. For example, I was able to duplicate the error using the example code by not providing a my_app module.
First, make sure your my_app.erl file exports an out/1 function. Here's a trivial one that just returns a 405 error for all requests:
-module(my_app).
-export([out/1]).
out(_Arg) ->
{status, 405}.
Compile your my_app.erl file and put the compiled my_app.beam file either in a load path already known to the Erlang runtime, or in a directory you add to the load path. In your code it appears you're trying the latter approach, since you're specifically adding an ebin_dir with this Yaws global configuration directive:
GconfList = [{ebin_dir, ["/Users/someuser/yawsembedded/ebin"]}],
You need to verify that the /Users/someuser/yawsembedded/ebin directory exists, and that the compiled my_app.beam file is located there.

External function call Erlang

I'm trying to call a function (from an external module) in erlang. both beam files are located in the same directory.
-module(drop2).
-export([fall_velocity/1]).
fall_velocity(Distance) -> math:sqrt(2 * 9.8 * Distance).
Then I'm calling
-module(ask).
-export([term/0]).
term() ->
Input = io:read("Enter {x,distance} ? >>"),
Term = element(2,Input),
drop2:fall_velocity(Term).
it gives the following error.I tested individual modules for errors. it is compiling with out any errors or warning.
Eshell V5.10.2 (abort with ^G)
1> ask:term().
Enter {x,distance} ? >>{test,10}.
** exception error: an error occurred when evaluating an arithmetic expression
in function drop2:fall_velocity/1 (drop2.erl, line 3)
Not sure why it is throwing arithmetic expression error .
You could read the documentation to figure out that the result is {ok, Term}. You could try the io:read/1 function in the console, then you'd see following:
1> io:read("Enter > ").
Enter > {test, 42}.
{ok,{test,42}}
2>
That means that you need to deconstruct the result of io:read/1 differently, for example like this:
-module(ask).
-export([term/0]).
term() ->
{ok, {_, Distance}} = io:read("Enter {x, distance} > "),
drop2:fall_velocity(Distance).

Erlang: misunderstanding of an error that is connected with ranch

I am trying to make this application FIX protocol
I start the Erlang shell using erl -pa ./ebin -pa ebin ./deps/*/ebin.
And run the application like this: application:start(fix).
After that I invoke "start_listener" function like this: fix:start_listener().
As a result this mistake appears:
exception error: no match of right hand side value
{error,
{{shutdown,
{failed_to_start_child,ranch_acceptors_sup,
badarg}},
{child,undefined,
{ranch_listener_sup,fix_listener},
{ranch_listener_sup,start_link,
[fix_listener,10,ranch_tcp,
[{port,[8501]}],
fix_server,[]]},
permanent,5000,supervisor,
[ranch_listener_sup]}}}
in function fix:start_listener/0 (src/fix.erl, line 21)
What does it all mean? And how to fix this mistake?
My code is:
`-module(fix).
-author('Max Lapshin <max#maxidoors.ru>').
-include("log.hrl").
% -include("../include/admin.hrl").
-include("../include/business.hrl").
-compile(export_all).
%% #doc Start acceptor with `ranch' on port, specified in application environment under fix_port%%
-spec start_listener() -> {ok, pid()}.
start_listener() ->
application:start(ranch),
Spec = ranch:child_spec(fix_listener, 10,
ranch_tcp, [{port, fix:get_value(fix_port)}],
fix_server, []
),
{ok, Pid} = supervisor:start_child(fix_sup, Spec),
error_logger:info_msg("Starting FIX server on port ~p~n",[fix:get_value(fix_port)]),
{ok, Pid}.
`
This is a piece of code that shows a mistake.
This is incorrect:
[{port,[8501]}]
Port value must be an integer.
Your fix:get_value function returns list [8501] instead 8501 and you get this badarg error.

Meck behaving strangely for multiple mocked modules

I have following module
-module(bhavcopy_downloader).
-export([download/2]).
download(From, SaveTo) ->
{ok, {{Status, _}, _, Body}} = lhttpc:request(From, "GET", [], infinity),
case Status of
200 -> file:write(SaveTo, Body),
true;
_ -> false
end.
And following tests for the above code
file_download_test_() ->
{foreach,
fun() ->
meck:new(lhttpc)
meck:new(file, [unstick])
end,
fun(_) ->
meck:unload(file),
meck:unload(lhttpc)
end,
{"saves the file at specified location",
fun() ->
meck:expect(lhttpc, request, 4, {ok, {{200, "OK"}, [], <<"response">>}}),
meck:expect(file, write_file, fun(Path, Data) ->
?assertEqual(Path, "~/Downloads/data-downloader/test.html"),
?assertEqual(Data, <<"response">>)
end),
?assertEqual(true, bhavcopy_downloader:download("http://google.com", "~/Downloads/data-downloader/test.html")),
?assert(meck:validate(file))
end}]
}.
When I run the tests I get following error (only part of the error pasted below for brevity). Looking at the error below, I am kind of feeling that file module is not being mocked (or the mock of file module being overridden when I set the other mock using meck:new(lhttpc). What could be going wrong here?
=ERROR REPORT==== 16-Feb-2013::20:17:24 ===
** Generic server file_meck terminating
** Last message in was {'EXIT',<0.110.0>,
{compile_forms,
{error,
[{[],
[{none,compile,
{crash,beam_asm,
{undef,
[{file,get_cwd,[],[]},
{filename,absname,1,
[{file,"filename.erl"},{line,67}]},
{compile,beam_asm,1,
[{file,"compile.erl"},{line,1245}]},
{compile,'-internal_comp/4-anonymous-1-',2,
[{file,"compile.erl"},{line,273}]},
{compile,fold_comp,3,
[{file,"compile.erl"},{line,291}]},
{compile,internal_comp,4,
[{file,"compile.erl"},{line,275}]},
{compile,'-do_compile/2-anonymous-0-',2,
[{file,"compile.erl"},{line,152}]}]}}}]}],
[{"src/lhttpc_types.hrl",
[{31,erl_lint,{new_builtin_type,{boolean,0}}},
{31,erl_lint,{renamed_type,bool,boolean}}]}]}}}
This is a catch 22 in Meck, caused by the fact that Meck uses the Erlang compiler, which in turns uses the file module. When Meck tries recompile the file module it needs the file module (through the compiler) and thus crashes.
As of this moment, Meck doesn't handle mocking the file module. Your best alternative is to wrap the file module calls in another module and mock this module instead.
(It is theoretically possible to fix this in Meck by using the internals of the compiler and the code server instead, for example erlang:load_module/2, however this is quite tricky and needs to be designed and tested well)

Resources