-module(client).
-export([start/2, loop/2]).
start(Node, User) ->
%% start linked processes on client and server to get notice if
%% client disconnects and properly handle the logged in status
process_flag(trap_exit, true),
Client = server:start_on_node(Node, client, undef),
link(Client),
%% store the client pid in the client database to find the correct
%% user on the exit message from the client
cldb:set_client_pid(User, Client),
Server = spawn_link(client, loop, [Client, User]),
%% update the server process_id in the state of the client process,
%% so that the client process knows its direct counterpart on the
%% server
case server:rpc(Client, {change_state, Server}) of
{ok} ->
{ok, Client};
Why ->
{error, {unknown_error, Why}}
end.
execute(Client, F) ->
%% execute F() with error handling
%% (sends error message on exception)
try F() of
Result ->
Client ! {ok, Result}
catch
_: Why ->
Client ! {error, Why}
end.
loop(Client, User) ->
%% main loop for client module in server, handle the commands from
%% the logged_in client
receive
{register, Name, Password} ->
case cldb:check_rights(User) of
admin -> execute(Client, fun() -> cldb:register(Name, Password, none) end);
_ -> Client ! {error, {no_rights}}
end;
list ->
execute(Client, fun() -> media:all() end);
get_votes ->
execute(Client, fun() -> cldb:get_votes(User) end);
{vote, Artist, Title} ->
%% only allow voting if user has at least one vote
case cldb:dec_vote(User) of
{ok} -> execute(Client, fun() -> media:vote(Artist, Title) end);
_ -> Client ! {error, no_votes_available}
end;
{devote, Artist, Title} ->
%% only allow devoting if user has at least one vote
case cldb:dec_vote(User) of
{ok} -> execute(Client, fun() -> media:devote(Artist, Title) end);
_ -> Client ! {error, no_votes_available}
end;
Cmd ->
%% fallback for error messages
Client ! {error, {unknown_command, Cmd}}
end,
loop(Client, User).