Create subject subsystem on server
This commit is contained in:
parent
68c55573de
commit
d2a479f691
@ -39,7 +39,7 @@ handle_info({'EXIT', Pid, Reason},
|
|||||||
Response = case Reason of
|
Response = case Reason of
|
||||||
{response, Value} -> Value;
|
{response, Value} -> Value;
|
||||||
_ ->
|
_ ->
|
||||||
io:format("Request handling error: ~p~n", [Reason]),
|
io:format("Error handling request: ~p~n", [Reason]),
|
||||||
{error, serverError}
|
{error, serverError}
|
||||||
end,
|
end,
|
||||||
send(Socket, TransactionId, Response),
|
send(Socket, TransactionId, Response),
|
||||||
@ -63,6 +63,13 @@ handle_request(Request) ->
|
|||||||
|
|
||||||
map_request({ping, 'NULL'}) ->
|
map_request({ping, 'NULL'}) ->
|
||||||
{response, {ack, 'NULL'}};
|
{response, {ack, 'NULL'}};
|
||||||
|
map_request({logSession, {'Session', Subject, Type, Timestamp, Minutes}}) ->
|
||||||
|
Session = {unicode:characters_to_list(Subject),
|
||||||
|
Type, Timestamp, Minutes},
|
||||||
|
case subject_router:log_session(Session) of
|
||||||
|
ok -> {response, {ack, 'NULL'}};
|
||||||
|
{error, invalid_subject} -> {response, {error, invalidArguments}}
|
||||||
|
end;
|
||||||
map_request(_) ->
|
map_request(_) ->
|
||||||
{response, {error, invalidArguments}}.
|
{response, {error, invalidArguments}}.
|
||||||
|
|
||||||
|
@ -9,7 +9,11 @@
|
|||||||
start(_StartType, _StartArgs) ->
|
start(_StartType, _StartArgs) ->
|
||||||
Port = application:get_env(study_system_server, port, 12888),
|
Port = application:get_env(study_system_server, port, 12888),
|
||||||
{ok, CertDir} = application:get_env(study_system_server, cert_dir),
|
{ok, CertDir} = application:get_env(study_system_server, cert_dir),
|
||||||
proto_sup:start_link(Port, CertDir).
|
{ok, _Pid} = pg:start(study_system_server),
|
||||||
|
study_system_server_sup:start_link(Port, CertDir),
|
||||||
|
subject_sup:start_subject("Cybernetics"),
|
||||||
|
subject_sup:start_subject("Physics"),
|
||||||
|
subject_sup:start_subject("Linguistics").
|
||||||
|
|
||||||
stop(_State) ->
|
stop(_State) ->
|
||||||
ok.
|
ok.
|
||||||
|
35
server/src/study_system_server_sup.erl
Normal file
35
server/src/study_system_server_sup.erl
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
% Copyright (c) Camden Dixie O'Brien
|
||||||
|
% SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
-module(study_system_server_sup).
|
||||||
|
-behaviour(supervisor).
|
||||||
|
|
||||||
|
-export([start_link/2]).
|
||||||
|
-export([init/1]).
|
||||||
|
|
||||||
|
start_link(Port, CertDir) ->
|
||||||
|
supervisor:start_link({local, ?MODULE}, ?MODULE, [Port, CertDir]).
|
||||||
|
|
||||||
|
init([Port, CertDir]) ->
|
||||||
|
SupFlags = #{strategy => one_for_one,
|
||||||
|
intensity => 5,
|
||||||
|
period => 10},
|
||||||
|
ChildSpecs = [#{id => subject_router,
|
||||||
|
start => {subject_router, start_link, []},
|
||||||
|
restart => permanent,
|
||||||
|
shutdown => 5000,
|
||||||
|
type => worker,
|
||||||
|
modules => [subject_router]},
|
||||||
|
#{id => subject_sup,
|
||||||
|
start => {subject_sup, start_link, []},
|
||||||
|
restart => permanent,
|
||||||
|
shutdown => 5000,
|
||||||
|
type => supervisor,
|
||||||
|
modules => [subject_sup]},
|
||||||
|
#{id => proto_sup,
|
||||||
|
start => {proto_sup, start_link, [Port, CertDir]},
|
||||||
|
restart => permanent,
|
||||||
|
shutdown => 5000,
|
||||||
|
type => supervisor,
|
||||||
|
modules => [proto_sup]}],
|
||||||
|
{ok, {SupFlags, ChildSpecs}}.
|
75
server/src/subject_router.erl
Normal file
75
server/src/subject_router.erl
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
% Copyright (c) Camden Dixie O'Brien
|
||||||
|
% SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
-module(subject_router).
|
||||||
|
-behaviour(gen_server).
|
||||||
|
|
||||||
|
-export([start_link/0, log_session/1]).
|
||||||
|
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||||
|
terminate/2, code_change/3]).
|
||||||
|
|
||||||
|
start_link() ->
|
||||||
|
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
||||||
|
|
||||||
|
log_session(Session) ->
|
||||||
|
gen_server:call(?MODULE, {log_session, Session}).
|
||||||
|
|
||||||
|
init([]) ->
|
||||||
|
{MonitorRef, Pids} = pg:monitor(study_system_server, subject_servers),
|
||||||
|
SubjectTable = ets:new(subject_table, [private]),
|
||||||
|
register_servers(SubjectTable, Pids),
|
||||||
|
{ok, #{monitor_ref => MonitorRef,
|
||||||
|
subject_table => SubjectTable}}.
|
||||||
|
|
||||||
|
handle_call({log_session, {Subject, Type, Timestamp, Minutes}},
|
||||||
|
_From, State = #{subject_table := SubjectTable}) ->
|
||||||
|
case ets:lookup(SubjectTable, Subject) of
|
||||||
|
[{Subject, Pid}] ->
|
||||||
|
Pid ! {new_session, Type, Timestamp, Minutes},
|
||||||
|
{reply, ok, State};
|
||||||
|
[] ->
|
||||||
|
{reply, {error, invalid_subject}, State}
|
||||||
|
end;
|
||||||
|
handle_call(_Request, _From, State) ->
|
||||||
|
{reply, ok, State}.
|
||||||
|
|
||||||
|
handle_cast(_Msg, State) ->
|
||||||
|
{noreply, State}.
|
||||||
|
|
||||||
|
handle_info({Ref, join, subject_servers, Pids},
|
||||||
|
State = #{monitor_ref := MonitorRef,
|
||||||
|
subject_table := SubjectTable})
|
||||||
|
when Ref =:= MonitorRef ->
|
||||||
|
register_servers(SubjectTable, Pids),
|
||||||
|
{noreply, State};
|
||||||
|
handle_info({Ref, leave, subject_servers, Pids},
|
||||||
|
State = #{monitor_ref := MonitorRef,
|
||||||
|
subject_table := SubjectTable})
|
||||||
|
when Ref =:= MonitorRef ->
|
||||||
|
deregister_servers(SubjectTable, Pids),
|
||||||
|
{noreply, State};
|
||||||
|
handle_info(_Info, State) ->
|
||||||
|
{noreply, State}.
|
||||||
|
|
||||||
|
terminate(_Reason, _State) ->
|
||||||
|
ok.
|
||||||
|
|
||||||
|
code_change(_OldVsn, State, _Extra) ->
|
||||||
|
{ok, State}.
|
||||||
|
|
||||||
|
register_servers(SubjectTable, Pids) ->
|
||||||
|
[register_server(SubjectTable, Pid) || Pid <- Pids].
|
||||||
|
|
||||||
|
register_server(SubjectTable, Pid) ->
|
||||||
|
try
|
||||||
|
{subject, Subject} = gen_server:call(Pid, get_subject),
|
||||||
|
ets:insert(SubjectTable, {Subject, Pid})
|
||||||
|
catch
|
||||||
|
_:_ -> ok
|
||||||
|
end.
|
||||||
|
|
||||||
|
deregister_servers(SubjectTable, Pids) ->
|
||||||
|
[deregister_server(SubjectTable, Pid) || Pid <- Pids].
|
||||||
|
|
||||||
|
deregister_server(SubjectTable, Pid) ->
|
||||||
|
ets:match_delete(SubjectTable, {'_', Pid}).
|
39
server/src/subject_server.erl
Normal file
39
server/src/subject_server.erl
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
% Copyright (c) Camden Dixie O'Brien
|
||||||
|
% SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
-module(subject_server).
|
||||||
|
-behaviour(gen_server).
|
||||||
|
|
||||||
|
-export([start_link/1]).
|
||||||
|
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||||
|
terminate/2, code_change/3]).
|
||||||
|
|
||||||
|
start_link(Subject) ->
|
||||||
|
gen_server:start_link(?MODULE, Subject, []).
|
||||||
|
|
||||||
|
init(Subject) ->
|
||||||
|
pg:join(study_system_server, subject_servers, self()),
|
||||||
|
{ok, #{subject => Subject}}.
|
||||||
|
|
||||||
|
handle_call(get_subject, _From, State = #{subject := Subject}) ->
|
||||||
|
{reply, {subject, Subject}, State};
|
||||||
|
handle_call(_Request, _From, State) ->
|
||||||
|
{reply, ok, State}.
|
||||||
|
|
||||||
|
handle_cast(_Msg, State) ->
|
||||||
|
{noreply, State}.
|
||||||
|
|
||||||
|
handle_info({new_session, Type, Timestamp, Minutes},
|
||||||
|
State = #{subject := Subject}) ->
|
||||||
|
io:format(
|
||||||
|
"Received new ~p session: type ~p, timestamp ~p, minutes ~p~n",
|
||||||
|
[Subject, Type, Timestamp, Minutes]),
|
||||||
|
{noreply, State};
|
||||||
|
handle_info(_Info, State) ->
|
||||||
|
{noreply, State}.
|
||||||
|
|
||||||
|
terminate(_Reason, _State) ->
|
||||||
|
ok.
|
||||||
|
|
||||||
|
code_change(_OldVsn, State, _Extra) ->
|
||||||
|
{ok, State}.
|
25
server/src/subject_sup.erl
Normal file
25
server/src/subject_sup.erl
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
% Copyright (c) Camden Dixie O'Brien
|
||||||
|
% SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
-module(subject_sup).
|
||||||
|
-behaviour(supervisor).
|
||||||
|
|
||||||
|
-export([start_link/0, init/1, start_subject/1]).
|
||||||
|
|
||||||
|
start_link() ->
|
||||||
|
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||||
|
|
||||||
|
init([]) ->
|
||||||
|
SupFlags = #{strategy => simple_one_for_one,
|
||||||
|
intensity => 5,
|
||||||
|
period => 10},
|
||||||
|
ChildSpec = #{id => subject_server,
|
||||||
|
start => {subject_server, start_link, []},
|
||||||
|
restart => permanent,
|
||||||
|
shutdown => 5000,
|
||||||
|
type => worker,
|
||||||
|
modules => [subject_server]},
|
||||||
|
{ok, {SupFlags, [ChildSpec]}}.
|
||||||
|
|
||||||
|
start_subject(Subject) ->
|
||||||
|
supervisor:start_child(?MODULE, [Subject]).
|
Loading…
x
Reference in New Issue
Block a user