From e3fecc7fd50b25f44fb83c7bbac02d53a7af411c Mon Sep 17 00:00:00 2001 From: Uriel Fanelli Date: Sat, 10 May 2025 21:08:23 +0200 Subject: [PATCH] /index handler added --- src/activitypub_server.app.src | 2 ++ src/activitypub_server_app.erl | 7 ++++- src/hello_handler.erl | 2 +- src/index_handler.erl | 55 ++++++++++++++++++++++++++++++++++ src/timeline_db.erl | 28 +++++++++++++++++ start.sh | 2 ++ 6 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 src/index_handler.erl create mode 100644 src/timeline_db.erl create mode 100755 start.sh diff --git a/src/activitypub_server.app.src b/src/activitypub_server.app.src index d43a585..824cc30 100644 --- a/src/activitypub_server.app.src +++ b/src/activitypub_server.app.src @@ -6,6 +6,8 @@ activitypub_server_app, activitypub_server_sup, hello_handler, + timeline_db, + user_db, webfinger_handler ]}, {registered, []}, diff --git a/src/activitypub_server_app.erl b/src/activitypub_server_app.erl index 854c43b..3a1b712 100644 --- a/src/activitypub_server_app.erl +++ b/src/activitypub_server_app.erl @@ -11,12 +11,17 @@ start(_Type, _Args) -> %% creiamo un utente di test, solo per vedere se mnesia va user_db:init(), + timeline_db:init(), + +%% aggiungiamo un paio di utenti di esempio. user_db:add_user(<<"admin">>, #{email => <<"admin@example.com">>}), + user_db:add_user(<<"alice">>, #{email => <<"alice@example.com">>}), Dispatch = cowboy_router:compile([ {'_', [ {"/", hello_handler, []}, - {"/.well-known/webfinger", webfinger_handler, []} + {"/.well-known/webfinger", webfinger_handler, []}, + {"/index", index_handler, []} %% per /index del server ]} ]), {ok, _} = cowboy:start_clear( diff --git a/src/hello_handler.erl b/src/hello_handler.erl index 0fd929e..b0c88c4 100644 --- a/src/hello_handler.erl +++ b/src/hello_handler.erl @@ -10,4 +10,4 @@ init(Req, State) -> <<"Hello, world!">>, Req ), - {ok, Resp, State}. + {ok, Resp, State}. \ No newline at end of file diff --git a/src/index_handler.erl b/src/index_handler.erl new file mode 100644 index 0000000..680c8ad --- /dev/null +++ b/src/index_handler.erl @@ -0,0 +1,55 @@ +%% index_handler.erl +-module(index_handler). +-behaviour(cowboy_handler). +-export([init/2]). + +init(Req, State) -> + {ok, Body, Req2} = cowboy_req:read_body(Req), + Activity = jsx:decode(Body, [return_maps]), + + case validate_activity(Activity) of + false -> + {ok, Resp} = cowboy_req:reply(400, #{}, <<"Invalid ActivityPub message">>, Req2), + {ok, Resp, State}; + true -> + io:format("Activity: ~p~n", [Activity]), + To = maps:get(<<"to">>, Activity, []), + io:format("To: ~p~n", [To]), + case has_local_recipient(To) of + true -> + {ok, Resp} = cowboy_req:reply(200, #{}, <<"Delivered to local user">>, Req2), + {ok, Resp, State}; + false -> + timeline_db:add_message(Activity), + {ok, Resp} = cowboy_req:reply(202, #{}, <<"Saved to global timeline">>, Req2), + {ok, Resp, State} + end + end. + +%% Controlla se un destinatario è un utente locale +is_local_user(Dest) when is_binary(Dest) -> + io:format("Controllo utente locale: ~p~n", [Dest]), + user_db:get_user(Dest) =/= not_found; +is_local_user(_) -> + false. + +%% Controlla se almeno uno dei destinatari è locale +has_local_recipient(To) when is_list(To) -> + lists:any(fun is_local_user/1, To); +has_local_recipient(To) when is_binary(To) -> + is_local_user(To); +has_local_recipient(_) -> + false. + + + +%% vediamo di controllare se ci sono i campi obbligatori minimi di ActivityPub: + +validate_activity(Activity) when is_map(Activity) -> + maps:is_key(<<"type">>, Activity) andalso + maps:is_key(<<"to">>, Activity) andalso + maps:is_key(<<"actor">>, Activity) andalso + maps:is_key(<<"object">>, Activity) andalso + maps:is_key(<<"content">>, Activity). + + diff --git a/src/timeline_db.erl b/src/timeline_db.erl new file mode 100644 index 0000000..25922d6 --- /dev/null +++ b/src/timeline_db.erl @@ -0,0 +1,28 @@ +%% timeline_db.erl +-module(timeline_db). +-export([init/0, add_message/1, all_messages/0]). + +-record(global_message, {id, activity, timestamp}). + +init() -> + %% Crea la tabella Mnesia se non esiste + mnesia:create_table(global_message, [ + {attributes, record_info(fields, global_message)}, + {disc_copies, [node()]} + ]). + +add_message(Activity) -> + %% Crea un ID unico e un timestamp per il messaggio + Id = erlang:unique_integer([monotonic, positive]), + Timestamp = erlang:system_time(microsecond), + F = fun() -> + mnesia:write(#global_message{id=Id, activity=Activity, timestamp=Timestamp}) + end, + mnesia:transaction(F). + +all_messages() -> + F = fun() -> + mnesia:match_object(#global_message{id = '_', activity = '_', timestamp = '_'}) + end, + {atomic, Messages} = mnesia:transaction(F), + Messages. diff --git a/start.sh b/start.sh new file mode 100755 index 0000000..b19d1a9 --- /dev/null +++ b/start.sh @@ -0,0 +1,2 @@ +rebar3 compile +rebar3 shell --apps activitypub_server