Skip to content
Permalink
Browse files
Run erl_tidy on modified source files
```erlang
lists:foreach(
  fun (F) -> erl_tidy:file(F, [{backups, false}, keep_unused]) end,
  string:split(
    string:trim(
      os:cmd("git diff --name-only origin/master | grep \".erl$\"")
    ),
    "\n",
    all
  )
).
```
  • Loading branch information
etrepum committed Mar 12, 2019
1 parent 8892431 commit 69d6df7fe02990ebbf8c836215d26a1e1939716a
Showing 15 changed files with 2,741 additions and 2,354 deletions.

Large diffs are not rendered by default.

@@ -1,4 +1,3 @@

%% Trivial web storage app. It's available over both HTTP (port 8442)
%% and HTTPS (port 8443). You use a PUT to store items, a GET to
%% retrieve them and DELETE to delete them. The HTTP POST method is
@@ -34,113 +33,102 @@

-module(https_store).

-export([start/0,
stop/0,
dispatch/1,
loop/1
]).
-export([dispatch/1, loop/1, start/0, stop/0]).

-define(HTTP_OPTS, [
{loop, {?MODULE, dispatch}},
{port, 8442},
{name, http_8442}
]).
-define(HTTP_OPTS,
[{loop, {?MODULE, dispatch}}, {port, 8442},
{name, http_8442}]).

-define(HTTPS_OPTS, [
{loop, {?MODULE, dispatch}},
{port, 8443},
{name, https_8443},
{ssl, true},
{ssl_opts, [
{certfile, "server_cert.pem"},
{keyfile, "server_key.pem"}]}
]).
-define(HTTPS_OPTS,
[{loop, {?MODULE, dispatch}}, {port, 8443},
{name, https_8443}, {ssl, true},
{ssl_opts,
[{certfile, "server_cert.pem"},
{keyfile, "server_key.pem"}]}]).

-record(sd, {http, https}).

-record(resource, {type, data}).

start() ->
{ok, Http} = mochiweb_http:start(?HTTP_OPTS),
{ok, Https} = mochiweb_http:start(?HTTPS_OPTS),
SD = #sd{http=Http, https=Https},
Pid = spawn_link(fun() ->
ets:new(?MODULE, [named_table]),
loop(SD)
end),
SD = #sd{http = Http, https = Https},
Pid = spawn_link(fun () ->
ets:new(?MODULE, [named_table]), loop(SD)
end),
register(http_store, Pid),
ok.

stop() ->
http_store ! stop,
ok.
stop() -> http_store ! stop, ok.

dispatch(Req) ->
case mochiweb_request:get(method, Req) of
'GET' ->
get_resource(Req);
'PUT' ->
put_resource(Req);
'DELETE' ->
delete_resource(Req);
_ ->
Headers = [{"Allow", "GET,PUT,DELETE"}],
mochiweb_request:respond({405, Headers, "405 Method Not Allowed\r\n"}, Req)
'GET' -> get_resource(Req);
'PUT' -> put_resource(Req);
'DELETE' -> delete_resource(Req);
_ ->
Headers = [{"Allow", "GET,PUT,DELETE"}],
mochiweb_request:respond({405, Headers,
"405 Method Not Allowed\r\n"},
Req)
end.

get_resource(Req) ->
Path = mochiweb_request:get(path, Req),
case ets:lookup(?MODULE, Path) of
[{Path, #resource{type=Type, data=Data}}] ->
mochiweb_request:ok({Type, Data}, Req);
[] ->
mochiweb_request:respond({404, [], "404 Not Found\r\n"}, Req)
[{Path, #resource{type = Type, data = Data}}] ->
mochiweb_request:ok({Type, Data}, Req);
[] ->
mochiweb_request:respond({404, [], "404 Not Found\r\n"},
Req)
end.

put_resource(Req) ->
ContentType = case mochiweb_request:get_header_value("Content-Type", Req) of
undefined ->
"application/octet-stream";
S ->
S
end,
Resource = #resource{type=ContentType, data=mochiweb_request:recv_body(Req)},
http_store ! {self(), {put, mochiweb_request:get(path, Req), Resource}},
ContentType = case
mochiweb_request:get_header_value("Content-Type", Req)
of
undefined -> "application/octet-stream";
S -> S
end,
Resource = #resource{type = ContentType,
data = mochiweb_request:recv_body(Req)},
http_store !
{self(),
{put, mochiweb_request:get(path, Req), Resource}},
Pid = whereis(http_store),
receive
{Pid, created} ->
mochiweb_request:respond({201, [], "201 Created\r\n"}, Req);
{Pid, updated} ->
mochiweb_request:respond({200, [], "200 OK\r\n"}, Req)
{Pid, created} ->
mochiweb_request:respond({201, [], "201 Created\r\n"},
Req);
{Pid, updated} ->
mochiweb_request:respond({200, [], "200 OK\r\n"}, Req)
end.

delete_resource(Req) ->
http_store ! {self(), {delete, mochiweb_request:get(path, Req)}},
http_store !
{self(), {delete, mochiweb_request:get(path, Req)}},
Pid = whereis(http_store),
receive
{Pid, ok} ->
mochiweb_request:respond({200, [], "200 OK\r\n"}, Req)
{Pid, ok} ->
mochiweb_request:respond({200, [], "200 OK\r\n"}, Req)
end.

loop(#sd{http=Http, https=Https} = SD) ->
loop(#sd{http = Http, https = Https} = SD) ->
receive
stop ->
ok = mochiweb_http:stop(Http),
ok = mochiweb_http:stop(Https),
exit(normal);
{From, {put, Key, Val}} ->
Exists = ets:member(?MODULE, Key),
ets:insert(?MODULE, {Key, Val}),
case Exists of
true ->
From ! {self(), updated};
false ->
From ! {self(), created}
end;
{From, {delete, Key}} ->
ets:delete(?MODULE, Key),
From ! {self(), ok};
_ ->
ignore
stop ->
ok = mochiweb_http:stop(Http),
ok = mochiweb_http:stop(Https),
exit(normal);
{From, {put, Key, Val}} ->
Exists = ets:member(?MODULE, Key),
ets:insert(?MODULE, {Key, Val}),
case Exists of
true -> From ! {self(), updated};
false -> From ! {self(), created}
end;
{From, {delete, Key}} ->
ets:delete(?MODULE, Key), From ! {self(), ok};
_ -> ignore
end,
?MODULE:loop(SD).

(?MODULE):loop(SD).
@@ -18,64 +18,62 @@
%% response. if you do that then control flow returns to the proper place,
%% and keep alives work like they would if you hadn't hibernated.

-export([ start/1, loop/1
]).
-export([loop/1, start/1]).

%% internal export (so hibernate can reach it)
-export([ resume/3
]).
-export([resume/3]).

-define(LOOP, {?MODULE, loop}).

start(Options = [{port, _Port}]) ->
mochiweb_http:start([{name, ?MODULE}, {loop, ?LOOP} | Options]).
mochiweb_http:start([{name, ?MODULE}, {loop, ?LOOP}
| Options]).

loop(Req) ->
Path = mochiweb_request:get(path, Req),
case string:tokens(Path, "/") of
["longpoll" | RestOfPath] ->
%% the "reentry" is a continuation -- what @mochiweb_http@
%% needs to do to start its loop back at the top
Reentry = mochiweb_http:reentry(?LOOP),

%% here we could send a message to some other process and hope
%% to get an interesting message back after a while. for
%% simplicity let's just send ourselves a message after a few
%% seconds
erlang:send_after(2000, self(), "honk honk"),

%% since we expect to wait for a long time before getting a
%% reply, let's hibernate. memory usage will be minimized, so
%% we won't be wasting memory just sitting in a @receive@
proc_lib:hibernate(?MODULE, resume, [Req, RestOfPath, Reentry]),

%% we'll never reach this point, and this function @loop/1@
%% won't ever return control to @mochiweb_http@. luckily
%% @resume/3@ will take care of that.
io:format("not gonna happen~n", []);

_ ->
ok(Req, io_lib:format("some other page: ~p", [Path]))
["longpoll" | RestOfPath] ->
%% the "reentry" is a continuation -- what @mochiweb_http@
%% needs to do to start its loop back at the top
Reentry = mochiweb_http:reentry(?LOOP),
%% here we could send a message to some other process and hope
%% to get an interesting message back after a while. for
%% simplicity let's just send ourselves a message after a few
%% seconds
erlang:send_after(2000, self(), "honk honk"),
%% since we expect to wait for a long time before getting a
%% reply, let's hibernate. memory usage will be minimized, so
%% we won't be wasting memory just sitting in a @receive@
proc_lib:hibernate(?MODULE, resume,
[Req, RestOfPath, Reentry]),
%% we'll never reach this point, and this function @loop/1@
%% won't ever return control to @mochiweb_http@. luckily
%% @resume/3@ will take care of that.
io:format("not gonna happen~n", []);
_ ->
ok(Req, io_lib:format("some other page: ~p", [Path]))
end,

io:format("restarting loop normally in ~p~n", [Path]),
ok.

%% this is the function that's called when a message arrives.
resume(Req, RestOfPath, Reentry) ->
receive
Msg ->
Text = io_lib:format("wake up message: ~p~nrest of path: ~p", [Msg, RestOfPath]),
ok(Req, Text)
Msg ->
Text =
io_lib:format("wake up message: ~p~nrest of path: ~p",
[Msg, RestOfPath]),
ok(Req, Text)
end,

%% if we didn't call @Reentry@ here then the function would finish and the
%% process would exit. calling @Reentry@ takes care of returning control
%% to @mochiweb_http@
io:format("reentering loop via continuation in ~p~n", [mochiweb_request:get(path, Req)]),
io:format("reentering loop via continuation in "
"~p~n",
[mochiweb_request:get(path, Req)]),
Reentry(Req).

ok(Req, Response) ->
mochiweb_request:ok(
{_ContentType = "text/plain", _Headers = [], Response},
Req).
mochiweb_request:ok({_ContentType = "text/plain",
_Headers = [], Response},
Req).

0 comments on commit 69d6df7

Please sign in to comment.