Import the initial dudeswave code.
At this point it handles only GETs, giving back plain text responses in case of errors. The intention is to also produce some static pages for those, where the CSS we will chose applies. Other APIs will be managed through their respective handlers, whose routes will be setup before this one.main
parent
14e6c3cc94
commit
1f243b16d3
|
@ -0,0 +1,7 @@
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
all:
|
||||||
|
${MAKE} -C src
|
||||||
|
|
||||||
|
clean:
|
||||||
|
${MAKE} -C src clean
|
|
@ -0,0 +1,12 @@
|
||||||
|
{application,dudeswave,
|
||||||
|
[{description,"The dudeswave web experience"},
|
||||||
|
{vsn,"1.0.0"},
|
||||||
|
{modules,[dudeswave,dudeswave_app,dudeswave_handler,dudeswave_supervisor]},
|
||||||
|
{registered,[]},
|
||||||
|
{applications,[kernel,stdlib,erts,cowboy,ranch]},
|
||||||
|
{mod,{dudeswave_app,[]}},
|
||||||
|
{env, [
|
||||||
|
{ip,"127.0.0.1"},
|
||||||
|
{port,8080},
|
||||||
|
]},
|
||||||
|
{start_phases,[]}]}.
|
|
@ -0,0 +1,15 @@
|
||||||
|
{application,dudeswave,
|
||||||
|
[{description,"The dudeswave web experience"},
|
||||||
|
{vsn,"1.0.0"},
|
||||||
|
{modules,[dudeswave,dudeswave_app,bigweb_handler,bigweb_supervisor]},
|
||||||
|
{registered,[]},
|
||||||
|
{applications,[kernel,stdlib,erts,cowboy,ranch]},
|
||||||
|
{mod,{bigweb_app,[]}},
|
||||||
|
{env, [
|
||||||
|
{proxy_host,"gemini.abiscuola.com"},
|
||||||
|
{ip,"127.0.0.1"},
|
||||||
|
{port,10443},
|
||||||
|
{certfile, "/var/_erlang/cert/www.abiscuola.com.crt"},
|
||||||
|
{keyfile, "/var/_erlang/private/www.abiscuola.com.key"}
|
||||||
|
]},
|
||||||
|
{start_phases,[]}]}.
|
|
@ -0,0 +1,16 @@
|
||||||
|
.PHONY: all clean
|
||||||
|
.SUFFIXES: .erl .beam
|
||||||
|
|
||||||
|
ERLC?= erlc -server
|
||||||
|
|
||||||
|
OBJS= dudeswave.beam dudeswave_app.beam
|
||||||
|
OBJS+= dudeswave_supervisor.beam dudeswave_handler.beam
|
||||||
|
|
||||||
|
all: ${OBJS}
|
||||||
|
|
||||||
|
.erl.beam:
|
||||||
|
${ERLC} ${ERLOPTS} ${ERLFLAGS} $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.beam
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
%
|
||||||
|
% Copyright (c) 2024 Andrea Biscuola <a@abiscuola.com>
|
||||||
|
%
|
||||||
|
% Permission to use, copy, modify, and distribute this software for any
|
||||||
|
% purpose with or without fee is hereby granted, provided that the above
|
||||||
|
% copyright notice and this permission notice appear in all copies.
|
||||||
|
%
|
||||||
|
% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
%
|
||||||
|
-module(dudeswave).
|
||||||
|
|
||||||
|
-behaviour(gen_server).
|
||||||
|
|
||||||
|
% Server start function
|
||||||
|
-export([start_link/0]).
|
||||||
|
|
||||||
|
% Module callbacks
|
||||||
|
-export([init/1, handle_call/3, handle_cast/2, terminate/2]).
|
||||||
|
|
||||||
|
%
|
||||||
|
% Startup functions
|
||||||
|
%
|
||||||
|
|
||||||
|
start_link() ->
|
||||||
|
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
||||||
|
|
||||||
|
init([]) ->
|
||||||
|
process_flag(trap_exit, true),
|
||||||
|
|
||||||
|
{ok, 0}.
|
||||||
|
|
||||||
|
%
|
||||||
|
% Callbacks
|
||||||
|
%
|
||||||
|
|
||||||
|
handle_call(_Msg, _From, State) -> {noreply, State}.
|
||||||
|
|
||||||
|
handle_cast(_Msg, State) -> {noreply, State}.
|
||||||
|
|
||||||
|
terminate(_Reason, _N) -> ok.
|
|
@ -0,0 +1,44 @@
|
||||||
|
%
|
||||||
|
% Copyright (c) 2024 Andrea Biscuola <a@abiscuola.com>
|
||||||
|
%
|
||||||
|
% Permission to use, copy, modify, and distribute this software for any
|
||||||
|
% purpose with or without fee is hereby granted, provided that the above
|
||||||
|
% copyright notice and this permission notice appear in all copies.
|
||||||
|
%
|
||||||
|
% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
%
|
||||||
|
-module(dudeswave_app).
|
||||||
|
-behaviour(application).
|
||||||
|
|
||||||
|
-export([start/2, stop/1]).
|
||||||
|
|
||||||
|
start(_Type, StartArgs) ->
|
||||||
|
{ok, Addr} = case application:get_env(ip) of
|
||||||
|
{ok, AddrConf} -> inet:parse_address(AddrConf);
|
||||||
|
undefined -> undefined
|
||||||
|
end,
|
||||||
|
|
||||||
|
{ok, Port} = application:get_env(port),
|
||||||
|
{ok, Bucket} = application:get_env(bucket),
|
||||||
|
|
||||||
|
Dispatch = cowboy_router:compile([
|
||||||
|
{'_', [{"/", dudeswave_handler, #{bucket => Bucket}}]}
|
||||||
|
]),
|
||||||
|
|
||||||
|
{ok, ListenerPid} = cowboy:start_tls(dudeswave_listener, [
|
||||||
|
{port, Port},
|
||||||
|
{ip, Addr}
|
||||||
|
], #{env => #{dispatch => Dispatch}}),
|
||||||
|
|
||||||
|
link(ListenerPid),
|
||||||
|
|
||||||
|
dudeswave_supervisor:start_link(StartArgs).
|
||||||
|
|
||||||
|
stop(_State) ->
|
||||||
|
cowboy:stop_listener(dudeswave_listener).
|
|
@ -0,0 +1,89 @@
|
||||||
|
%
|
||||||
|
% Copyright (c) 2024 Andrea Biscuola <a@abiscuola.com>
|
||||||
|
%
|
||||||
|
% Permission to use, copy, modify, and distribute this software for any
|
||||||
|
% purpose with or without fee is hereby granted, provided that the above
|
||||||
|
% copyright notice and this permission notice appear in all copies.
|
||||||
|
%
|
||||||
|
% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
%
|
||||||
|
-module(dudeswave_handler).
|
||||||
|
-moduledoc """
|
||||||
|
The dudeswave GET handler.
|
||||||
|
|
||||||
|
This module handles only fetching and returning resources. Anything
|
||||||
|
else is considered a bad request, apart from the obvious case of 500
|
||||||
|
(internal server error) and 404 (not found).
|
||||||
|
""".
|
||||||
|
|
||||||
|
-behaviour(cowboy_handler).
|
||||||
|
|
||||||
|
-export([init/2, terminate/3]).
|
||||||
|
|
||||||
|
-include_lib("storage/include/storage.hrl").
|
||||||
|
|
||||||
|
%
|
||||||
|
% Protocol functions
|
||||||
|
%
|
||||||
|
|
||||||
|
init(Req, State) ->
|
||||||
|
{ok, Bucket} = maps:find(bucket, State),
|
||||||
|
Path = cowboy_req:path(Req),
|
||||||
|
|
||||||
|
case cowboy_req:method(Req) of
|
||||||
|
<<"GET">> ->
|
||||||
|
%
|
||||||
|
% Fetch the page from storage
|
||||||
|
%
|
||||||
|
case storage:read(Bucket, Path) of
|
||||||
|
{ok, []} ->
|
||||||
|
Resp = cowboy_req:reply(404,
|
||||||
|
#{<<"content-type">> => <<"text/plain">>}, <<"Not found">>, Req),
|
||||||
|
{ok, Resp, State};
|
||||||
|
%
|
||||||
|
% If we get a resource, send it back to the client with
|
||||||
|
% it's proper mime type.
|
||||||
|
%
|
||||||
|
{ok, [R]} ->
|
||||||
|
{Mime, Bin} = get_final_object(R),
|
||||||
|
Resp = cowboy_req:reply(200, #{<<"content-type">> => Mime},
|
||||||
|
Bin, Req),
|
||||||
|
{ok, Resp, State};
|
||||||
|
{error, _} ->
|
||||||
|
Resp = cowboy_req:reply(500, #{<<"content-type">> => <<"text/plain">>},
|
||||||
|
<<"Internal server error">>, Req),
|
||||||
|
{ok, Resp, State}
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
Resp = cowboy_req:reply(400, #{<<"content-type">> => <<"text/plain">>},
|
||||||
|
<<"Bad request">>, Req),
|
||||||
|
{ok, Resp, State}
|
||||||
|
end.
|
||||||
|
|
||||||
|
terminate(_Reason, _Req, _State) -> ok.
|
||||||
|
|
||||||
|
-spec get_final_object(Record) -> {Mime, Bin} when
|
||||||
|
Record :: storage:object(),
|
||||||
|
Mime :: binary(),
|
||||||
|
Bin :: binary().
|
||||||
|
|
||||||
|
get_final_object(Record) ->
|
||||||
|
case lists:keyfind(mime, 1, Record#object.metadata) of
|
||||||
|
%
|
||||||
|
% We do not know the object mime type. This should never
|
||||||
|
% happen.
|
||||||
|
%
|
||||||
|
false ->
|
||||||
|
{<<"application/octect-stream">>, Record#object.value};
|
||||||
|
%
|
||||||
|
% Everything else, just return it as is.
|
||||||
|
%
|
||||||
|
{mime, Mime} ->
|
||||||
|
{list_to_binary(Mime), Record#object.value}
|
||||||
|
end.
|
|
@ -0,0 +1,31 @@
|
||||||
|
%
|
||||||
|
% Copyright (c) 2024 Andrea Biscuola <a@abiscuola.com>
|
||||||
|
%
|
||||||
|
% Permission to use, copy, modify, and distribute this software for any
|
||||||
|
% purpose with or without fee is hereby granted, provided that the above
|
||||||
|
% copyright notice and this permission notice appear in all copies.
|
||||||
|
%
|
||||||
|
% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
%
|
||||||
|
-module(dudeswave_supervisor).
|
||||||
|
-behaviour(supervisor).
|
||||||
|
|
||||||
|
-export([start/0,
|
||||||
|
start_link/1,
|
||||||
|
init/1]).
|
||||||
|
|
||||||
|
start() ->
|
||||||
|
spawn(fun() -> supervisor:start_link({local, ?MODULE}, ?MODULE, _Arg = []) end).
|
||||||
|
|
||||||
|
start_link(Args) ->
|
||||||
|
supervisor:start_link({local, ?MODULE}, ?MODULE, Args).
|
||||||
|
|
||||||
|
init([]) ->
|
||||||
|
{ok, {{one_for_one, 3, 10}, [{tag1, {dudeswave, start_link, []}, permanent,
|
||||||
|
10000, worker, [dudeswave]}]}}.
|
Loading…
Reference in New Issue