First code
parent
f2738c4ae8
commit
b8d35fcc67
|
@ -0,0 +1,34 @@
|
||||||
|
# File di build e compilazione
|
||||||
|
/_build/
|
||||||
|
*.beam
|
||||||
|
*.o
|
||||||
|
*.plt
|
||||||
|
|
||||||
|
# Dipendenze scaricate
|
||||||
|
/deps/
|
||||||
|
|
||||||
|
# File di test e log
|
||||||
|
.eunit/
|
||||||
|
logs/
|
||||||
|
erl_crash.dump
|
||||||
|
|
||||||
|
# File generati da strumenti
|
||||||
|
.rebar/
|
||||||
|
.rebar3/
|
||||||
|
.cover/
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# File temporanei di Mnesia (database locale)
|
||||||
|
Mnesia.*
|
||||||
|
|
||||||
|
# File temporanei di editor
|
||||||
|
*~
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
|
# File temporanei di sistema
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Escludi solo i file beam da ebin, NON l'intera cartella (serve per i .app)
|
||||||
|
ebin/*.beam
|
|
@ -0,0 +1,4 @@
|
||||||
|
{deps, [
|
||||||
|
{cowboy, "2.10.0"},
|
||||||
|
{jsx, "3.1.0"}
|
||||||
|
]}.
|
|
@ -0,0 +1,17 @@
|
||||||
|
{"1.2.0",
|
||||||
|
[{<<"cowboy">>,{pkg,<<"cowboy">>,<<"2.10.0">>},0},
|
||||||
|
{<<"cowlib">>,{pkg,<<"cowlib">>,<<"2.12.1">>},1},
|
||||||
|
{<<"jsx">>,{pkg,<<"jsx">>,<<"3.1.0">>},0},
|
||||||
|
{<<"ranch">>,{pkg,<<"ranch">>,<<"1.8.0">>},1}]}.
|
||||||
|
[
|
||||||
|
{pkg_hash,[
|
||||||
|
{<<"cowboy">>, <<"FF9FFEFF91DAE4AE270DD975642997AFE2A1179D94B1887863E43F681A203E26">>},
|
||||||
|
{<<"cowlib">>, <<"A9FA9A625F1D2025FE6B462CB865881329B5CAFF8F1854D1CBC9F9533F00E1E1">>},
|
||||||
|
{<<"jsx">>, <<"D12516BAA0BB23A59BB35DCCAF02A1BD08243FCBB9EFE24F2D9D056CCFF71268">>},
|
||||||
|
{<<"ranch">>, <<"8C7A100A139FD57F17327B6413E4167AC559FBC04CA7448E9BE9057311597A1D">>}]},
|
||||||
|
{pkg_hash_ext,[
|
||||||
|
{<<"cowboy">>, <<"3AFDCCB7183CC6F143CB14D3CF51FA00E53DB9EC80CDCD525482F5E99BC41D6B">>},
|
||||||
|
{<<"cowlib">>, <<"163B73F6367A7341B33C794C4E88E7DBFE6498AC42DCD69EF44C5BC5507C8DB0">>},
|
||||||
|
{<<"jsx">>, <<"0C5CC8FDC11B53CC25CF65AC6705AD39E54ECC56D1C22E4ADB8F5A53FB9427F3">>},
|
||||||
|
{<<"ranch">>, <<"49FBCFD3682FAB1F5D109351B61257676DA1A2FDBE295904176D5E521A2DDFE5">>}]}
|
||||||
|
].
|
|
@ -0,0 +1,20 @@
|
||||||
|
{application, activitypub_server,
|
||||||
|
[
|
||||||
|
{description, "A simple ActivityPub server in Erlang"},
|
||||||
|
{vsn, "0.1.0"},
|
||||||
|
{modules, [
|
||||||
|
activitypub_server_app,
|
||||||
|
activitypub_server_sup,
|
||||||
|
hello_handler,
|
||||||
|
webfinger_handler
|
||||||
|
]},
|
||||||
|
{registered, []},
|
||||||
|
{applications, [
|
||||||
|
kernel,
|
||||||
|
stdlib,
|
||||||
|
cowboy,
|
||||||
|
jsx
|
||||||
|
]},
|
||||||
|
{mod, {activitypub_server_app, []}},
|
||||||
|
{env, []}
|
||||||
|
]}.
|
|
@ -0,0 +1,31 @@
|
||||||
|
%% activitypub_server_app.erl
|
||||||
|
%% Modulo principale dell'applicazione OTP
|
||||||
|
|
||||||
|
-module(activitypub_server_app).
|
||||||
|
-behaviour(application).
|
||||||
|
|
||||||
|
%% Esporta le funzioni richieste dal behaviour application
|
||||||
|
-export([start/2, stop/1]).
|
||||||
|
|
||||||
|
start(_Type, _Args) ->
|
||||||
|
|
||||||
|
%% creiamo un utente di test, solo per vedere se mnesia va
|
||||||
|
user_db:init(),
|
||||||
|
user_db:add_user(<<"admin">>, #{email => <<"admin@example.com">>}),
|
||||||
|
|
||||||
|
Dispatch = cowboy_router:compile([
|
||||||
|
{'_', [
|
||||||
|
{"/", hello_handler, []},
|
||||||
|
{"/.well-known/webfinger", webfinger_handler, []}
|
||||||
|
]}
|
||||||
|
]),
|
||||||
|
{ok, _} = cowboy:start_clear(
|
||||||
|
http_listener,
|
||||||
|
[{port, 8080}],
|
||||||
|
#{env => #{dispatch => Dispatch}}
|
||||||
|
),
|
||||||
|
activitypub_server_sup:start_link().
|
||||||
|
|
||||||
|
|
||||||
|
stop(_State) ->
|
||||||
|
ok.
|
|
@ -0,0 +1,13 @@
|
||||||
|
-module(activitypub_server_sup).
|
||||||
|
-behaviour(supervisor).
|
||||||
|
|
||||||
|
-export([start_link/0]).
|
||||||
|
-export([init/1]).
|
||||||
|
|
||||||
|
start_link() ->
|
||||||
|
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||||
|
|
||||||
|
|
||||||
|
init([]) ->
|
||||||
|
{ok, {{one_for_one, 1, 5}, []}}.
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
-module(hello_handler).
|
||||||
|
-behaviour(cowboy_handler).
|
||||||
|
|
||||||
|
-export([init/2]).
|
||||||
|
|
||||||
|
init(Req, State) ->
|
||||||
|
{ok, Resp} = cowboy_req:reply(
|
||||||
|
200,
|
||||||
|
#{<<"content-type">> => <<"text/plain">>},
|
||||||
|
<<"Hello, world!">>,
|
||||||
|
Req
|
||||||
|
),
|
||||||
|
{ok, Resp, State}.
|
|
@ -0,0 +1,5 @@
|
||||||
|
-module(start_server).
|
||||||
|
-export([main/0]).
|
||||||
|
|
||||||
|
main() ->
|
||||||
|
application:ensure_all_started(activitypub_server).
|
|
@ -0,0 +1,35 @@
|
||||||
|
-module(user_db).
|
||||||
|
-export([init/0, add_user/2, get_user/1, all_users/0]).
|
||||||
|
|
||||||
|
-record(user, {username, data}).
|
||||||
|
|
||||||
|
init() ->
|
||||||
|
mnesia:create_schema([node()]),
|
||||||
|
mnesia:start(),
|
||||||
|
mnesia:create_table(user, [
|
||||||
|
{attributes, record_info(fields, user)},
|
||||||
|
{disc_copies, [node()]}
|
||||||
|
]).
|
||||||
|
|
||||||
|
add_user(Username, Data) ->
|
||||||
|
F = fun() ->
|
||||||
|
mnesia:write(#user{username=Username, data=Data})
|
||||||
|
end,
|
||||||
|
mnesia:transaction(F).
|
||||||
|
|
||||||
|
get_user(Username) ->
|
||||||
|
F = fun() ->
|
||||||
|
case mnesia:read({user, Username}) of
|
||||||
|
[User] -> {ok, User};
|
||||||
|
[] -> not_found
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
{atomic, Result} = mnesia:transaction(F),
|
||||||
|
Result.
|
||||||
|
|
||||||
|
all_users() ->
|
||||||
|
F = fun() ->
|
||||||
|
mnesia:match_object(#user{username='_', data='_'})
|
||||||
|
end,
|
||||||
|
{atomic, Users} = mnesia:transaction(F),
|
||||||
|
Users.
|
|
@ -0,0 +1,77 @@
|
||||||
|
%% webfinger_handler.erl
|
||||||
|
%% Handler per l'endpoint /.well-known/webfinger
|
||||||
|
-module(webfinger_handler).
|
||||||
|
-behaviour(cowboy_handler).
|
||||||
|
|
||||||
|
%% Cowboy vuole che esportiamo la funzione init/2
|
||||||
|
-export([init/2]).
|
||||||
|
|
||||||
|
init(Req, State) ->
|
||||||
|
Params = cowboy_req:parse_qs(Req),
|
||||||
|
Resource = proplists:get_value(<<"resource">>, Params),
|
||||||
|
|
||||||
|
case Resource of
|
||||||
|
undefined ->
|
||||||
|
{ok, Resp} = cowboy_req:reply(
|
||||||
|
400,
|
||||||
|
#{<<"content-type">> => <<"application/json">>},
|
||||||
|
<<"{\"error\": \"Missing resource parameter\"}">>,
|
||||||
|
Req
|
||||||
|
),
|
||||||
|
{ok, Resp, State};
|
||||||
|
_ ->
|
||||||
|
case parse_acct(Resource) of
|
||||||
|
{ok, Username, Domain} ->
|
||||||
|
%% Qui interroghiamo Mnesia!
|
||||||
|
case user_db:get_user(Username) of
|
||||||
|
{ok, _User} ->
|
||||||
|
ActorUrl = <<"https://", Domain/binary, "/users/", Username/binary>>,
|
||||||
|
WebfingerMap = #{
|
||||||
|
<<"subject">> => <<"acct:", Username/binary, "@", Domain/binary>>,
|
||||||
|
<<"links">> => [
|
||||||
|
#{
|
||||||
|
<<"rel">> => <<"self">>,
|
||||||
|
<<"type">> => <<"application/activity+json">>,
|
||||||
|
<<"href">> => ActorUrl
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
Json = jsx:encode(WebfingerMap),
|
||||||
|
{ok, Resp} = cowboy_req:reply(
|
||||||
|
200,
|
||||||
|
#{<<"content-type">> => <<"application/jrd+json">>},
|
||||||
|
Json,
|
||||||
|
Req
|
||||||
|
),
|
||||||
|
{ok, Resp, State};
|
||||||
|
not_found ->
|
||||||
|
{ok, Resp} = cowboy_req:reply(
|
||||||
|
404,
|
||||||
|
#{<<"content-type">> => <<"application/json">>},
|
||||||
|
<<"{\"error\": \"User not found\"}">>,
|
||||||
|
Req
|
||||||
|
),
|
||||||
|
{ok, Resp, State}
|
||||||
|
end;
|
||||||
|
error ->
|
||||||
|
{ok, Resp} = cowboy_req:reply(
|
||||||
|
400,
|
||||||
|
#{<<"content-type">> => <<"application/json">>},
|
||||||
|
<<"{\"error\": \"Invalid resource format\"}">>,
|
||||||
|
Req
|
||||||
|
),
|
||||||
|
{ok, Resp, State}
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
%% Funzione di utilità per estrarre username e dominio da "acct:username@domain"
|
||||||
|
parse_acct(<<"acct:", Rest/binary>>) ->
|
||||||
|
case binary:split(Rest, <<"@">>) of
|
||||||
|
[Username, Domain] when Username =/= <<>>, Domain =/= <<>> ->
|
||||||
|
{ok, Username, Domain};
|
||||||
|
_ ->
|
||||||
|
error
|
||||||
|
end;
|
||||||
|
parse_acct(_) ->
|
||||||
|
error.
|
Loading…
Reference in New Issue