python -m SimpleHTTPServer
Eshell V5.9.1 (abort with ^G)
1> httpc:request("http://localhost:8000").
** exception exit: {noproc,
{gen_server,call,
[httpc_manager,
{request,
{request,undefined,<0.32.0>,0,http,
{"localhost",8000},
"/",[],get,
{http_request_h,undefined,"keep-alive",undefined,
undefined,undefined,undefined,undefined,undefined,
undefined,...},
{[],[]},
{http_options,"HTTP/1.1",infinity,true,
{essl,[]},
undefined,false,infinity,...},
"http://localhost:8000",[],none,[],1340149470691,
undefined,undefined,false}},
infinity]}}
in function gen_server:call/3 (gen_server.erl, line 188)
in call from httpc:handle_request/9 (httpc.erl, line 562)
Eshell V5.9.1 (abort with ^G)
1> httpc:request("http://localhost:8000").
** exception exit: {noproc,
{gen_server,call,
...
in function gen_server:call/3 (gen_server.erl, line 188)
in call from httpc:handle_request/9 (httpc.erl, line 562)
noproc
means someone expected a process to be running, it wasn'thttpc
is a part of the inets
appinets
2> appmon:start().
{ok,<0.36.0>}
3> application:start(inets).
ok
4> httpc:request("http://localhost:8000").
{ok,{{"HTTP/1.0",200,"OK"},
[{"date","Wed, 20 Jun 2012 00:28:46 GMT"},
{"server","SimpleHTTP/0.6 Python/2.7.3"},
{"content-length","178"},
{"content-type","text/html; charset=UTF-8"}],
"<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\"><html>\n<title>Directory listing for /</title>\n<body>\n<h2>Directory listing for /</h2>\n<hr>\n<ul>\n</ul>\n<hr>\n</body>\n</html>\n"}}
1
, 2
, 45.5
hello
"hello"
<<"hello">>
{color, "red"}
["red", "green", "blue"]
Assigned:
X = 1.
Bad match:
X = 2.
** exception error: no match of right hand side value 2
Assigned:
{Y, Z} = {1, 2}.
Y = 1.
Z = 2.
Bad match:
{ok, Val} = {error, "oops"}.
** exception error: no match of right hand side value {error, "oops"}
Define a list:
L = [1, 2, 3].
Cons to construct a new list by appending head:
[0,1,2,3] = [0|L].
Cons pattern match to separate head and tail:
[H|T] = L,
H = 1,
T = [2,3].
lists
module provides useful higher order functions:
Increment = fun(X) -> X + 1 end,
[2,3,4] = lists:map(Increment, L).
erlc
monitor.erl
-module(monitor).
-export([run/0]).
run() ->
Result = httpc:request("http://localhost:8000"),
io:format("~n~p~n", [Result]),
timer:sleep(5000),
run().
run
is a function of "arity" 0 (no args)timer:sleep/1
[1] Slight exaggeration
-module(monitor).
-export([run/0]).
-define(URL, "http://localhost:8000").
-define(CHECK_DELAY, 5000).
run() ->
check(),
run_again().
check() ->
handle_result(request(?URL)).
request(URL) ->
httpc:request(URL).
handle_result(Result) ->
io:format("~n~p~n", [Result]).
run_again() ->
timer:sleep(Milliseconds),
run().
handle_result({ok, {{_Protocol, 200, _Msg}, _Headers, _Body}}) ->
io:format("~nSite is UP~n");
handle_result({ok, {{_Protocol, Code, Msg}, _Headers, _Body}}) ->
io:format("~nSite is DOWN: ~p~n", [{Code, Msg}]);
handle_result({error, Err}) ->
io:format("~nSite is DOWN: ~p~n", [Err]).
check() ->
handle_status(url_status(?URL)).
url_status(URL) ->
result_status(httpc:request(URL)).
result_status({ok, {{_Protocol, Code, Msg}, _Headers, _Body}}) ->
{ok, {Code, Msg}};
result_status({error, Err}) ->
{error, Err}.
handle_status({ok, {200, _Msg}}) ->
handle_site_up();
handle_status({ok, {Code, Msg}}) ->
handle_site_down({Code, Msg});
handle_status({error, Err}) ->
handle_site_down(Err).
handle_site_up() ->
e2_log:info("Site is UP").
handle_site_down(Err) ->
e2_log:error("Site is DOWN: ~p", [Err]).
spawn
or spawn_link
monitor.erl
-export([start/0]).
start() -> spawn(fun run/0).
fun run/0
is a reference to to run/0
http://21ccw.blogspot.com/2009/05/how-to-send-email-via-gmail-using.html
connect() ->
{ok, Socket} = ssl:connect("smtp.gmail.com", 465,
[{active, false}], 1000),
recv(Socket),
send(Socket, "HELO localhost"),
send(Socket, "AUTH LOGIN"),
send(Socket, binary_to_list(base64:encode("me@gmail.com"))),
send(Socket, binary_to_list(base64:encode("letmein"))),
send(Socket, "MAIL FROM: <me@gmail.com>"),
send(Socket, "RCPT TO: <you@mail.com>"),
send(Socket, "DATA"),
send_no_receive(Socket, "From: <me@gmail.com>"),
send_no_receive(Socket, "To: <you@mail.com>"),
send_no_receive(Socket, "Date: Tue, 20 Jun 2012 20:34:43 +0000"),
send_no_receive(Socket, "Subject: Hi!"),
send_no_receive(Socket, ""),
send_no_receive(Socket, "This was sent from Erlang. So simple!"),
send_no_receive(Socket, ""),
send(Socket, "."),
send(Socket, "QUIT"),
ssl:close(Socket).
The bug:
check() ->
lurking_evil(),
handle_status(url_status("http://localhost:8000/foo")).
lurking_evil() ->
crash_if_true(randomly_true()).
The result:
2> monitor:start().
<0.57.0>
Site is UP
Site is UP
Site is UP
8>
=ERROR REPORT==== 5-Jul-2012::11:34:50 ===
Error in process <0.57.0> with exit value: {lurking_evil,[{monitor,crash_if_true,1},{monitor,check,0},{monitor,run,0}]}
$ cd $E2_HOME
$ make new-project appid=monitor appdir=~/monitor-app
...
$ cd ~/monitor-app
$ make
...
$ make shell
...
1> application:start(monitor).
=INFO REPORT==== 20-Jun-2012::01:12:18 ===
TODO: configure top-level processes for your app
make
to perform various commandsnew-project
creates a basic Erlang applicationmake
builds the projectmake shell
runs the project in a shell-module(monitor_check).
-behavior(e2_task).
-export([start_link/0, handle_task/1]).
start_link() ->
e2_task:start_link(?MODULE, [], [{repeat, ?REPEAT_INTERVAL}]).
handle_task(State) ->
handle_status(url_status(?URL)),
{repeat, State}.
...
start_link/0
called by supervisor to start the taskhandle_task/1
callback performs the work-module(monitor_app).
-behavior(e2_application).
-export([init/0]).
init() ->
{ok, [monitor_check]}.
init/0
returns a list of app process specsmonitor_check:start_link/0
1> application:start(monitor).
ok
2>
=ERROR REPORT==== 20-Jun-2012::01:46:37 ===
** Generic server <0.40.0> terminating
** Last message in was timeout
** When Server state == {state,e2_task,
{state,monitor_check,[],false,undefined,5000},
'$task'}
** Reason for termination ==
** {noproc,
{gen_server,call,
[httpc_manager,
...
inets
{application, monitor,
[{description, "monitor app"},
{vsn, "1"},
{modules, []},
{registered, []},
{mod, {e2_application, [monitor_app]}},
{env, []},
{applications, [kernel, stdlib, inets]}]}.
applications
list (last line)1> application:start(monitor).
{error,{not_started,inets}}
2> monitor:start().
=INFO REPORT==== 20-Jun-2012::02:00:47 ===
Started inets
ok
3>
Site is UP
Site is UP
monitor:start/0
is a short-cut for "start monitor along with all its
dependencies"monitor
, check task is startedLast process is our monitor_check
task
Site is UP
Site is UP
=ERROR REPORT==== 20-Jun-2012::02:04:57 ===
** Generic server <0.99.0> terminating
** Last message in was '$task'
** When Server state == {state,e2_task,
{state,monitor_check,[],false,1340175847478,
5000},
undefined}
** Reason for termination ==
** {lurking_evil,[{monitor_check,crash_if_true,1,
...
Site is UP
Site is UP
[{monitor,
[{smtp_account, "ceug.monitor@gmail.com"},
{smtp_pwd, "sesame0620"},
{check_interval, 10},
{check_url, "http://localhost:8000/"},
{notify_email, ["ceug.monitor@gmail.com"]}]}].
-config
option$ make opts="-config priv/dev" shell
...
1> monitor:start().
INFO REPORT==== 20-Jun-2012::02:38:51 ===
Started inets
ok
2> application:get_all_env(monitor).
[{check_interval,10},
{check_url,"http://localhost:8000/"},
{smtp_pwd,"sesame0620"},
{included_applications,[]},
{notify_email,["ceug.monitor@gmail.com"]},
{smtp_account,"ceug.monitor@gmail.com"}]
...
handle_task(State) ->
handle_status(url_status(url())),
{repeat, State}.
url() ->
required_env(application:get_env(check_url), check_url).
required_env({ok, Val}, _Name) -> Val;
required_env(undefined, Name) -> error({required_env, Name}).
...
application:get_value/1
...
init([]) ->
{ok, #state{url=url()}}.
handle_task(#state{url=URL}=State) ->
handle_status(url_status(URL)),
{repeat, State}.
...
init/1
state
record-module(beer).
-export([new/1, rate/2, to_list/1]).
-record(beer, {name, rating}).
new(Name) -> #beer{name=Name}.
rate(Beer, Rating) -> Beer#beer{rating=Rating}.
to_list(#beer{name=Name, rating=Rating}) ->
[{name, Name}, {rating, Rating}].
In the shell:
1> B = beer:new("Smuttynose Old Brown Dog").
{beer,"Smuttynose Old Brown Dog",undefined}.
2> B2 = beer:rate(B, "pretty damn good").
{beer,"Smuttynose Old Brown Dog","pretty damn good"}.
3> beer:to_list(B2).
[{name,"Smuttynose Old Brown Dog"},
{rating,"pretty damn good"}]
monitor_check_sup.erl
-module(monitor_check_sup).
-behavior(e2_supervisor).
-export([start_link/0]).
start_link() ->
e2_supervisor:start_link(?MODULE, checks()).
checks() ->
check_specs(monitor:required_config(checks)).
check_specs(Checks) ->
[{{monitor_check, start_link, [URL, Interval]}, [{id, Id}]}
|| {Id, URL, Interval} <- Checks].
[{monitor,
[{smtp_account, "ceug.monitor@gmail.com"},
{smtp_pwd, "sesame0620"},
{checks,
[{foo, "http://localhost:8000/foo", 10},
{bar, "http://localhost:8000/bar", 20}]},
{notify_email, ["ceug.monitor@gmail.com"]}]}].
monitor_check.erl
-module(monitor_check).
-export([start_link/2]).
-export([init/1]).
start_link(URL, Interval) ->
e2_task:start_link(?MODULE, [URL], [{repeat, Interval * 1000}]).
init([URL]) ->
{ok, #state{url=URL}}.
...
URL
and Interval
now required as start argsmonitor_check_sup
on app startup-module(monitor_notify).
-behavior(e2_service).
-export([start_link/0, send_msg/3]).
-export([handle_msg/3]).
%%%------------- Public API (client context) ------------
start_link() ->
e2_service:start_link(?MODULE, [], [registered]).
send_msg(To, Subject, Body) ->
e2_service:cast(?MODULE, {send, To, Subject, Body}).
%%%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%%%~~~~~~~~~~~~~~~~~~~~ Ether Barrier ~~~~~~~~~~~~~~~~~~~~
%%%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%%%---------- Message Handlers (server context) ----------
handle_msg({send, To, Subject, Body}, _From, State) ->
e2_log:info({todo_send_email, To, Subject, Body, State}),
{noreply, State}.
start_link
starts the servicecall
sends a message and waits for a replycast
sends a message and doesn't waitinit
used to optionally initialize state in service contexthandle_msg
handles messages sent by the clientterminate
used to optionally handle process termination[1] Or you turn your computer off
[1] I don't actually have stickers :(
Table of Contents | t |
---|---|
Exposé | ESC |
Full screen slides | e |
Presenter View | p |
Source Files | s |
Slide Numbers | n |
Toggle screen blanking | b |
Show/hide slide context | c |
Notes | 2 |
Help | h |