Added UUID

main
Uriel Fanelli 2025-05-11 13:39:37 +02:00
parent 8b1fd3445a
commit 3d2b7a9c76
5 changed files with 101 additions and 20 deletions

View File

@ -2,7 +2,7 @@
"$schema": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#",
"title": "ActivityPub Note", "title": "ActivityPub Note",
"type": "object", "type": "object",
"required": ["type", "id", "content"], "required": ["type", "content"],
"properties": { "properties": {
"@context": { "type": "string" }, "@context": { "type": "string" },
"type": { "type": "string", "enum": ["Note"] }, "type": { "type": "string", "enum": ["Note"] },

View File

@ -1,4 +1,5 @@
{deps, [ {deps, [
{uuid_erl, "1.5.0"},
jsonlog, jsonlog,
jesse, jesse,
{cowboy, "2.10.0"}, {cowboy, "2.10.0"},

View File

@ -10,7 +10,7 @@
start(_Type, _Args) -> start(_Type, _Args) ->
%% creiamo un utente di test, solo per vedere se mnesia va %% creiamo un utente di test, solo per vedere se mnesia va
log_handler:init(), %% va per primo, se no, non logga l'avvio log_handler:start_link(), %% va per primo, se no, non logga l'avvio
db_organization:setup(), db_organization:setup(),
db_organization:init(), db_organization:init(),
users_local_check:check_ENV(), %% controlla le variabili d'ambiente users_local_check:check_ENV(), %% controlla le variabili d'ambiente

View File

@ -9,10 +9,13 @@ init(Req, State) ->
case json_validate:validate_activity(Body) of case json_validate:validate_activity(Body) of
ok -> ok ->
%% Decodifica il JSON già validato %% Decodifica il JSON già validato
Activity = jsx:decode(Body, [return_maps]), Activity0 = jsx:decode(Body, [return_maps]),
Host = cowboy_req:host(Req2),
Activity = ensure_id(Activity0, Host),
To = maps:get(<<"to">>, Activity, []), To = maps:get(<<"to">>, Activity, []),
case users_local_check:has_local_recipient(To) of case users_local_check:has_local_recipient(To) of
true -> true ->
log_handler:error("Delivered ~p", [Req2]),
cowboy_req:reply(200, #{}, <<"Delivered to local user">>, Req2), cowboy_req:reply(200, #{}, <<"Delivered to local user">>, Req2),
{ok, Req2, State}; {ok, Req2, State};
false -> false ->
@ -24,6 +27,7 @@ init(Req, State) ->
}), }),
case InsertResult of case InsertResult of
ok -> ok ->
log_handler:error("Saved in INBOX database ~p", [Req2]),
cowboy_req:reply(202, #{}, <<"Saved to global inbox">>, Req2), cowboy_req:reply(202, #{}, <<"Saved to global inbox">>, Req2),
{ok, Req2, State}; {ok, Req2, State};
{aborted, Reason} -> {aborted, Reason} ->
@ -37,6 +41,7 @@ init(Req, State) ->
end end
end; end;
{error, malformed_json} -> {error, malformed_json} ->
log_handler:error("Malformed JSON ricevuto da ~p", [Req2]),
cowboy_req:reply(400, #{}, <<"Malformed JSON">>, Req2), cowboy_req:reply(400, #{}, <<"Malformed JSON">>, Req2),
{ok, Req2, State}; {ok, Req2, State};
{error, missing_type} -> {error, missing_type} ->
@ -64,3 +69,23 @@ read_full_body(Req) ->
{Rest, FinalReq} = read_full_body(Req2), {Rest, FinalReq} = read_full_body(Req2),
{<<Data/binary, Rest/binary>>, FinalReq} {<<Data/binary, Rest/binary>>, FinalReq}
end. end.
ensure_id(Activity, Host) ->
case maps:is_key(<<"id">>, Activity) of
true -> Activity;
false ->
UUID = uuid_v4(),
UUIDBin = list_to_binary(UUID),
Id = <<"https://", Host/binary, "/activity/", UUIDBin/binary>>,
maps:put(<<"id">>, Id, Activity)
end.
uuid_v4() ->
<<A:32, B:16, C:16, D:16, E:48>> = crypto:strong_rand_bytes(16),
% Imposta i bit di versione e variant secondo lo standard UUID v4
C1 = (C band 16#0fff) bor 16#4000,
D1 = (D band 16#3fff) bor 16#8000,
lists:flatten(
io_lib:format("~8.16.0b-~4.16.0b-~4.16.0b-~4.16.0b-~12.16.0b", [A, B, C1, D1, E])
).

View File

@ -1,34 +1,89 @@
-module(log_handler). -module(log_handler).
-export([init/0, info/2, error/2, warning/2, debug/2, log_map/2]). -behaviour(gen_server).
init() -> %% API
ok = ensure_log_dir(), -export([start_link/0, stop/0, info/2, error/2, warning/2, debug/2, log_map/2]).
lists:foreach(fun(H) -> logger:remove_handler(H) end, logger:get_handler_ids()),
logger:add_handler(file, logger_std_h, #{
level => debug,
config => #{file => "log/erlang.json", sync_mode_qlen => 0},
formatter => {logger_formatter, #{}}
}),
ok.
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-define(LOG_FILE, "log/erlang.jsonl").
-record(state, {io_device}).
%%% API
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
stop() ->
gen_server:cast(?MODULE, stop).
info(Format, Args) -> info(Format, Args) ->
logger:info(Format, Args). log(<<"info">>, Format, Args).
error(Format, Args) -> error(Format, Args) ->
logger:error(Format, Args). log(<<"error">>, Format, Args).
warning(Format, Args) -> warning(Format, Args) ->
logger:warning(Format, Args). log(<<"warning">>, Format, Args).
debug(Format, Args) -> debug(Format, Args) ->
logger:debug(Format, Args). log(<<"debug">>, Format, Args).
%% Logga direttamente una mappa come evento JSON
log_map(Level, Map) when is_map(Map) -> log_map(Level, Map) when is_map(Map) ->
logger:log(Level, Map). gen_server:cast(?MODULE, {log_map, Level, Map}).
%%% Internal log helper
log(Level, Format, Args) ->
Msg = io_lib:format(Format, Args),
MsgBin = iolist_to_binary(Msg),
Map = #{
timestamp => erlang:system_time(millisecond),
level => Level,
message => MsgBin
},
gen_server:cast(?MODULE, {log_map, Level, Map}).
%%% gen_server callbacks
init([]) ->
ok = ensure_log_dir(),
case file:open(?LOG_FILE, [append, raw]) of
{ok, IoDevice} ->
{ok, #state{io_device=IoDevice}};
{error, Reason} ->
{stop, {file_open_failed, Reason}}
end.
handle_cast({log_map, _Level, Map}, State = #state{io_device=IoDevice}) ->
Json = jsx:encode(Map),
file:write(IoDevice, [Json, <<"\n">>]),
{noreply, State};
handle_cast(stop, State = #state{io_device=IoDevice}) ->
file:close(IoDevice),
{stop, normal, State};
handle_cast(_, State) ->
{noreply, State}.
handle_call(_Request, _From, State) ->
{reply, ok, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, State = #state{io_device=IoDevice}) ->
file:close(IoDevice),
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%% Utility
%% Utility per assicurarsi che la directory log/ esista
ensure_log_dir() -> ensure_log_dir() ->
case file:read_file_info("log") of case file:read_file_info("log") of
{ok, _} -> ok; {ok, _} -> ok;