From 2a392910b0812122713229306b4e91f9bfd696fb Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sat, 24 Oct 2015 15:58:32 +0200 Subject: Initial import --- mess_client.erl | 36 ++++++++++++++++++++++++++++++ mess_config.hrl | 2 ++ mess_interface.hrl | 24 ++++++++++++++++++++ mess_server.erl | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ user_interface.erl | 40 +++++++++++++++++++++++++++++++++ 5 files changed, 167 insertions(+) create mode 100644 mess_client.erl create mode 100644 mess_config.hrl create mode 100644 mess_interface.hrl create mode 100644 mess_server.erl create mode 100644 user_interface.erl diff --git a/mess_client.erl b/mess_client.erl new file mode 100644 index 0000000..4db8081 --- /dev/null +++ b/mess_client.erl @@ -0,0 +1,36 @@ +%%% The client process which runs on each user node + +-module(mess_client). +-export([client/2]). +-include("mess_interface.hrl"). + +client(Server_Node, Name) -> + {messenger, Server_Node} ! #logon{client_pid=self(), username=Name}, + await_result(), + client(Server_Node). + +client(Server_Node) -> + receive + logoff -> + exit(normal); + #message_to{to_name=ToName, message=Message} -> + {messenger, Server_Node} ! + #message{client_pid=self(), to_name=ToName, message=Message}, + await_result(); + {message_from, FromName, Message} -> + io:format("Message from ~p: ~p~n", [FromName, Message]) + end, + client(Server_Node). + +%%% wait for a response from the server +await_result() -> + receive + #abort_client{message=Why} -> + io:format("~p~n", [Why]), + exit(normal); + #server_reply{message=What} -> + io:format("~p~n", [What]) + after 5000 -> + io:format("No response from server~n", []), + exit(timeout) + end. diff --git a/mess_config.hrl b/mess_config.hrl new file mode 100644 index 0000000..90beea6 --- /dev/null +++ b/mess_config.hrl @@ -0,0 +1,2 @@ +%%% Conifigure the location of the server node, +-define(server_node, messenger@otto). diff --git a/mess_interface.hrl b/mess_interface.hrl new file mode 100644 index 0000000..56d82d5 --- /dev/null +++ b/mess_interface.hrl @@ -0,0 +1,24 @@ +%%% Message interface between client and server and client shell for +%%% messenger program + +%%% Messages from Client to server received in server/1 function. +-record(logon, {client_pid, username}). +-record(message, {client_pid, to_name, message}). +%%% {'EXIT', ClientPid, Reason} (client terminated ro unrechable.) + +%%% Messages from Server to Client, received in await_result/0 function +-record(abort_client, {message}). +%%% Messages are: user_exists_at_other_node, +%%% you_are_not_logged_on +-record(server_reply, {message}). +%%% Messages are: logged_on, +%%% receiver_not_found, +%%% sent (Message has been sent (no garantee) + +%%% Messages from Server to Client received in client/1 function +-record(message_from, {from_name, message}). + +%%% Messages from shell to Client received in client/1 function +%%% spawn(mess_client, client, [server_node(), Name]) +-record(message_to, {to_name, message}). +%%% logoff diff --git a/mess_server.erl b/mess_server.erl new file mode 100644 index 0000000..3a25a98 --- /dev/null +++ b/mess_server.erl @@ -0,0 +1,65 @@ +%%% This is the server process of the messenger service + +-module(mess_server). +-export([server_start/0, server/0]). +-include("mess_interface.hrl"). + +server() -> + process_flag(trap_exit, true), + server([]). + +%%% the user list has the format [{ClientPid1, Name1},{ClientPid2,Name2},...] +server(User_List) -> + io:format("User list = ~p~n", [User_List]), + receive + #logon{client_pid=From, username=Name} -> + New_User_List = server_logon(From, Name, User_List), + server(New_User_List); + {'EXIT', From, _} -> + New_User_List = server_logoff(From, User_List), + server(New_User_List); + #message{client_pid=From, to_name=ToName, message=Message} -> + server_transfer(From, ToName, Message, User_List), + server(User_List) + end. + +%%% Start the server +server_start() -> + register(messenger, spawn(?MODULE, server, [])). + +%%% Server adds a new user to the user list +server_logon(From, Name, User_List) -> + %% check if logged on anyone else + case lists:keymember(Name, 2, User_List) of + true -> + From ! #abort_client{message=user_exists_at_other_node}, + User_List; + false -> + From ! #server_reply{message=logged_on}, + link(From), + [{From, Name} | User_List] % add user to the list + end. + +%%% Server deletes a user from the user list +server_logoff(From, User_List) -> + lists:keydelete(From, 1, User_List). + +%%% Server transfers a message between user +server_transfer(From, To, Message, User_List) -> + %% check that the user is logged on and who he is + case lists:keysearch(From, 1, User_List) of + false -> + From ! #abort_client{message=you_are_not_logged_on}; + {value, {_, Name}} -> + server_transfer(From, Name, To, Message, User_List) + end. + +%%% If the user exists, send the message +server_transfer(From, Name, To, Message, User_List) -> + case lists:keysearch(To, 2, User_List) of + false -> + From ! #server_reply{message=receiver_not_found}; + {value, {ToPid, To}} -> + ToPid ! #message_from{from_name=Name, message=Message}, + From ! #server_reply{message=sent} + end. diff --git a/user_interface.erl b/user_interface.erl new file mode 100644 index 0000000..ccd77c6 --- /dev/null +++ b/user_interface.erl @@ -0,0 +1,40 @@ +%%% User interface to the messenger program + +%%% login(Name) +%%% One user at time can log in from each Erlang node in the +%%% system messenger: and choose a suitable Name. If the Name +%%% is already logged in at another node or if someone else is +%%% alreeady logged in at the same node, login will be rejected +%%% with a suitable error message. + +%%% logoff() +%%% Logs off anybody at the node + +%%% message(ToName, Message) +%%% sends Message to ToName. Error messages if the user of this +%%% function is not logged on or if ToName is not logged on at +%%% any node. + +-module(user_interface). +-export([logon/1, logoff/0, message/2]). +-include("mess_interface.hrl"). +-include("mess_config.hrl"). + +logon(Name) -> + case whereis(mess_client) of + undefined -> + register(mess_client, + spawn(mess_client, client, [?server_node, Name])); + _ -> already_logged_on + end. + +logoff() -> + mess_client ! logoff. + +message(ToName, Message) -> + case whereis(mess_client) of % Test if client is running + undefined -> + not_logged_on; + _ -> mess_client ! #message_to{to_name=ToName, message=Message}, + ok + end. -- cgit v1.2.3