From 68c55573de05293b43219fdf0a0320cf4ca22479 Mon Sep 17 00:00:00 2001 From: Camden Dixie O'Brien Date: Sat, 1 Mar 2025 17:22:31 +0000 Subject: [PATCH] Remove subject IDs and improve request handling --- client/src/activities_view.vala | 14 ++++---- client/src/activity.vala | 7 ++-- client/src/client.vala | 6 ++-- client/src/request.vala | 4 +-- client/src/response.vala | 17 ++++------ client/src/session_manager.vala | 2 +- server/asn1/StudySystemProtocol.asn1 | 5 ++- server/src/session_server.erl | 48 +++++++++++++++++++--------- server/src/session_sup.erl | 4 +-- 9 files changed, 60 insertions(+), 47 deletions(-) diff --git a/client/src/activities_view.vala b/client/src/activities_view.vala index bfdd123..a491eaa 100644 --- a/client/src/activities_view.vala +++ b/client/src/activities_view.vala @@ -16,12 +16,12 @@ namespace StudySystemClient { scrolled_window.add_css_class("card-container"); var activities = new Activity[] { - { 2, "Linguistics", ActivityType.EXERCISES }, - { 1, "Cybernetics", ActivityType.EXERCISES }, - { 2, "Linguistics", ActivityType.READING }, - { 0, "Physics", ActivityType.READING }, - { 1, "Cybernetics", ActivityType.READING }, - { 0, "Physics", ActivityType.EXERCISES }, + { "Linguistics", ActivityType.EXERCISES }, + { "Cybernetics", ActivityType.EXERCISES }, + { "Linguistics", ActivityType.READING }, + { "Physics", ActivityType.READING }, + { "Cybernetics", ActivityType.READING }, + { "Physics", ActivityType.EXERCISES }, }; foreach (var activity in activities) { var card = new ActivityCard(client, activity); @@ -42,7 +42,7 @@ namespace StudySystemClient { var text = new Gtk.Box(Gtk.Orientation.VERTICAL, 6); text.hexpand = true; - var subject = new Gtk.Label(activity.subject_name); + var subject = new Gtk.Label(activity.subject); subject.halign = Gtk.Align.START; subject.add_css_class("activity-subject"); text.append(subject); diff --git a/client/src/activity.vala b/client/src/activity.vala index 785795e..11a3429 100644 --- a/client/src/activity.vala +++ b/client/src/activity.vala @@ -1,14 +1,13 @@ namespace StudySystemClient { public struct Activity { - public int subject_id; - public string subject_name; + public string subject; public ActivityType type; public double priority; } public enum ActivityType { - EXERCISES, - READING; + READING = 0, + EXERCISES = 1; public string to_string() { switch (this) { diff --git a/client/src/client.vala b/client/src/client.vala index db65dfc..e383616 100644 --- a/client/src/client.vala +++ b/client/src/client.vala @@ -41,11 +41,11 @@ namespace StudySystemClient { } } - public async void log_session(int subject_id, ActivityType type, + public async void log_session(string subject, ActivityType type, int minutes) throws ClientError { var timestamp = new DateTime.now_utc().to_unix(); - var request = new Request.LogSession(subject_id, type, - timestamp, minutes); + var request + = new Request.LogSession(subject, type, timestamp, minutes); var response = yield connection.send(request); if (response is Response.Ack) { return; diff --git a/client/src/request.vala b/client/src/request.vala index 793b61c..d709f40 100644 --- a/client/src/request.vala +++ b/client/src/request.vala @@ -39,11 +39,11 @@ namespace StudySystemClient.Request { } public class LogSession : Body { - public LogSession(int subject_id, ActivityType type, + public LogSession(string subject, ActivityType type, int64 timestamp, int minutes) { var fields = new Der.Datum[] { - new Der.Integer(subject_id), + new Der.Utf8String(subject), new Der.Enumerated((int)type), new Der.Integer(timestamp), new Der.Integer(minutes), diff --git a/client/src/response.vala b/client/src/response.vala index 3dfb1e9..5e16bef 100644 --- a/client/src/response.vala +++ b/client/src/response.vala @@ -127,20 +127,17 @@ namespace StudySystemClient.Response { throws DecodeError { if (datum is Der.Sequence) { var fields = datum.value; - if (fields.length < 4) { + if (fields.length < 3) { throw new DecodeError.INVALID_BODY( - "Too few fields in Activity: %u (expected 4)", + "Too few fields in Activity: %u (expected 3)", fields.length); } - var subject_id = get_int("Activity.subjectId", fields[0]); - var subject_name - = get_string("Activity.subjectName", fields[1]); + var subject = get_string("Activity.subject", fields[0]); var activity_type - = get_activity_type("Activity.type", fields[2]); - var int_priority = get_int("Activity.priority", fields[3]); - var priority = (double)int_priority / 100.0; - return { subject_id, subject_name, activity_type, priority }; - + = get_activity_type("Activity.type", fields[1]); + var priority_int = get_int("Activity.priority", fields[2]); + var priority = (double)priority_int / 100.0; + return { subject, activity_type, priority }; } else { throw new DecodeError.INVALID_BODY( "Activity was not a SEQUENCE"); diff --git a/client/src/session_manager.vala b/client/src/session_manager.vala index 61807d7..bdecbcf 100644 --- a/client/src/session_manager.vala +++ b/client/src/session_manager.vala @@ -65,7 +65,7 @@ namespace StudySystemClient { public class SessionFactory { private const string CA_FILENAME = "/ca.pem"; private const string CERT_FILENAME = "/client.pem"; - private const uint TIMEOUT_S = 1; + private const uint TIMEOUT_S = 5; private InetSocketAddress host; private TlsCertificate cert; diff --git a/server/asn1/StudySystemProtocol.asn1 b/server/asn1/StudySystemProtocol.asn1 index 2addbef..9bc6272 100644 --- a/server/asn1/StudySystemProtocol.asn1 +++ b/server/asn1/StudySystemProtocol.asn1 @@ -6,7 +6,7 @@ ActivityType ::= ENUMERATED { } Session ::= SEQUENCE { - subjectId INTEGER, + subject UTF8String, type ActivityType, timestamp INTEGER, minutes INTEGER @@ -24,8 +24,7 @@ Request ::= SEQUENCE { } Activity ::= SEQUENCE { - subjectId INTEGER, - subjectName UTF8String, + subject UTF8String, type ActivityType, priority INTEGER } diff --git a/server/src/session_server.erl b/server/src/session_server.erl index 5c73f1d..4e44c7e 100644 --- a/server/src/session_server.erl +++ b/server/src/session_server.erl @@ -13,7 +13,8 @@ start_link(Socket) -> init(Socket) -> ok = ssl:setopts(Socket, [{active, true}]), - {ok, #{socket => Socket}}. + process_flag(trap_exit, true), + {ok, #{socket => Socket, transactions => #{}}}. handle_call(_Request, _From, State) -> {reply, ok, State}. @@ -21,21 +22,28 @@ handle_call(_Request, _From, State) -> handle_cast(_Msg, State) -> {noreply, State}. -handle_info({ssl, Socket, Data}, State) -> +handle_info({ssl, Socket, Data}, State = #{transactions := Transactions}) -> case 'StudySystemProtocol':decode('Request', Data) of {ok, {'Request', TransactionId, RequestBody}} -> - ResponseBody = map_request(RequestBody), - {ok, Encoded} = 'StudySystemProtocol':encode( - 'Response', - {'Response', TransactionId, ResponseBody}), - ok = ssl:send(Socket, Encoded); + Pid = spawn_link(fun() -> handle_request(RequestBody) end), + NewTransactions = maps:put(Pid, TransactionId, Transactions), + {noreply, State#{transactions := NewTransactions}}; {error, {asn1, _Reason}} -> - {ok, Encoded} = 'StudySystemProtocol':encode( - 'Response', - {'Response', -1, {error, invalidRequest}}), - ok = ssl:send(Socket, Encoded) - end, - {noreply, State}; + send(Socket, -1, {error, invalidRequest}), + {noreply, State} + end; +handle_info({'EXIT', Pid, Reason}, + State = #{socket := Socket, transactions := Transactions}) + when is_map_key(Pid, Transactions) -> + TransactionId = maps:get(Pid, Transactions), + Response = case Reason of + {response, Value} -> Value; + _ -> + io:format("Request handling error: ~p~n", [Reason]), + {error, serverError} + end, + send(Socket, TransactionId, Response), + {noreply, State#{transactions := maps:remove(Pid, Transactions)}}; handle_info({ssl_closed, _Socket}, State) -> {stop, normal, State}; handle_info({ssl_error, _Socket, _Reason}, State) -> @@ -49,7 +57,17 @@ terminate(_Reason, #{socket := Socket}) -> code_change(_OldVsn, State, _Extra) -> {ok, State}. +handle_request(Request) -> + timer:kill_after(500), + exit(map_request(Request)). + map_request({ping, 'NULL'}) -> - {ack, 'NULL'}; + {response, {ack, 'NULL'}}; map_request(_) -> - {error, invalidRequest}. + {response, {error, invalidArguments}}. + +send(Socket, TransactionId, Response) -> + {ok, Encoded} = 'StudySystemProtocol':encode( + 'Response', + {'Response', TransactionId, Response}), + ok = ssl:send(Socket, Encoded). diff --git a/server/src/session_sup.erl b/server/src/session_sup.erl index a2c5b67..45bd3be 100644 --- a/server/src/session_sup.erl +++ b/server/src/session_sup.erl @@ -11,8 +11,8 @@ start_link() -> init([]) -> SupFlags = #{strategy => simple_one_for_one, - intensity => 10, - period => 1}, + intensity => 5, + period => 10}, ChildSpec = #{id => session_server, start => {session_server, start_link, []}, restart => temporary,