From 1f243b16d366ac1b63342f9e1a090399f0b38d17 Mon Sep 17 00:00:00 2001 From: absc Date: Tue, 23 Jul 2024 22:52:57 +0200 Subject: [PATCH] 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. --- dudeswave/Makefile | 7 ++ dudeswave/ebin/dudeswave.app | 12 ++++ dudeswave/ebin/dudeswave.appE | 15 +++++ dudeswave/src/Makefile | 16 +++++ dudeswave/src/dudeswave.erl | 46 +++++++++++++ dudeswave/src/dudeswave_app.erl | 44 +++++++++++++ dudeswave/src/dudeswave_handler.erl | 89 ++++++++++++++++++++++++++ dudeswave/src/dudeswave_supervisor.erl | 31 +++++++++ 8 files changed, 260 insertions(+) create mode 100644 dudeswave/Makefile create mode 100644 dudeswave/ebin/dudeswave.app create mode 100644 dudeswave/ebin/dudeswave.appE create mode 100644 dudeswave/src/Makefile create mode 100644 dudeswave/src/dudeswave.erl create mode 100644 dudeswave/src/dudeswave_app.erl create mode 100644 dudeswave/src/dudeswave_handler.erl create mode 100644 dudeswave/src/dudeswave_supervisor.erl diff --git a/dudeswave/Makefile b/dudeswave/Makefile new file mode 100644 index 0000000..160022d --- /dev/null +++ b/dudeswave/Makefile @@ -0,0 +1,7 @@ +.PHONY: all clean + +all: + ${MAKE} -C src + +clean: + ${MAKE} -C src clean diff --git a/dudeswave/ebin/dudeswave.app b/dudeswave/ebin/dudeswave.app new file mode 100644 index 0000000..ce137e4 --- /dev/null +++ b/dudeswave/ebin/dudeswave.app @@ -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,[]}]}. diff --git a/dudeswave/ebin/dudeswave.appE b/dudeswave/ebin/dudeswave.appE new file mode 100644 index 0000000..f550b3d --- /dev/null +++ b/dudeswave/ebin/dudeswave.appE @@ -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,[]}]}. diff --git a/dudeswave/src/Makefile b/dudeswave/src/Makefile new file mode 100644 index 0000000..7c52e6a --- /dev/null +++ b/dudeswave/src/Makefile @@ -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 + diff --git a/dudeswave/src/dudeswave.erl b/dudeswave/src/dudeswave.erl new file mode 100644 index 0000000..9893223 --- /dev/null +++ b/dudeswave/src/dudeswave.erl @@ -0,0 +1,46 @@ +% +% Copyright (c) 2024 Andrea Biscuola +% +% 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. diff --git a/dudeswave/src/dudeswave_app.erl b/dudeswave/src/dudeswave_app.erl new file mode 100644 index 0000000..5d09989 --- /dev/null +++ b/dudeswave/src/dudeswave_app.erl @@ -0,0 +1,44 @@ +% +% Copyright (c) 2024 Andrea Biscuola +% +% 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). \ No newline at end of file diff --git a/dudeswave/src/dudeswave_handler.erl b/dudeswave/src/dudeswave_handler.erl new file mode 100644 index 0000000..7d45eaf --- /dev/null +++ b/dudeswave/src/dudeswave_handler.erl @@ -0,0 +1,89 @@ +% +% Copyright (c) 2024 Andrea Biscuola +% +% 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. \ No newline at end of file diff --git a/dudeswave/src/dudeswave_supervisor.erl b/dudeswave/src/dudeswave_supervisor.erl new file mode 100644 index 0000000..dad62ce --- /dev/null +++ b/dudeswave/src/dudeswave_supervisor.erl @@ -0,0 +1,31 @@ +% +% Copyright (c) 2024 Andrea Biscuola +% +% 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]}]}}. \ No newline at end of file