summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mess_client.erl36
-rw-r--r--mess_config.hrl2
-rw-r--r--mess_interface.hrl24
-rw-r--r--mess_server.erl65
-rw-r--r--user_interface.erl40
5 files changed, 167 insertions, 0 deletions
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.