Skip to content

Latest commit

 

History

History
96 lines (79 loc) · 3.3 KB

README.md

File metadata and controls

96 lines (79 loc) · 3.3 KB

Communication On FaceIn - This assignment is about how parts of FaceIn could be implemented in Erlang (see also the Prolog assignment about FaceIn).

Implementation

####start(N) function

start(Person) -> spawn(fun () -> 
	loop(dict:store(messageRefs,[],
		 dict:store(messages,[],
		 dict:store(friend_list,[],
		 dict:store(name, Person, 
		 dict:new()))))) end).

The start function spawns a new process that stores a database represented by a dictionary. The loop function is a blocking function that waits for requests from other processes.

####add_friend(P,F) function

% add a pid (F) to a pid's (P) firend list
add_friend(P,F) ->
	F ! {self(), get_name},
	receive
		{F, {ok,Name}} -> 
			P ! {self(),{add_friend,{Name,F}}},
			receive
				{P, ok} -> "friend added";
				{P, {error,Reason2}} -> Reason2
			end;
		{F, {error,Reason1}} -> Reason1
	end.

The add_friend function gets the name of the F process to store it into the friend list. After it receives the response, it send a request to process P to add the name and PID to the freind list.

####broadcast(P, M, R) function

%broadcast a message (M) to all of (P) friends within radius (R)
broadcast(P, M, R) ->
	MessageRef = make_ref(),
	{ok, Name} = name(P),
	rpc_no_response(P, {broadcast_msg, {Name,MessageRef, M, R}}).

The broadcast function creates a distinct message reference and passes to every connected friend, which in turn pass the message along until the radius R is 0.

###Request handling

The get_friends, add_friends are pretty straight forward, the first one gets the friend list from the dictionary, and the second one add a friend to the friend list. The database is updated by creating a new dictionary from the old one and recursively calling loop with the new dictionary.

The most important part is probably the brodcast_msg request. Every process receives a package with the process that sent the message, the message reference so that we don't add duplicates to the message list, the actual message string, and the TTL represented by the radius R.

We check that the radius R is greater than 0. If it is, we pass the message on by submiting a request to all the friends from the process who received the message.

case R > 0 of
				true -> 	
					%send to friends with (R-1)
					{ok, FriendList} = dict:find(friend_list, PersonDatabase),
					lists:map(fun({FriendName,Pid}) -> Pid ! {self(), {broadcast_msg, {P,MessageRef, M, R-1}}}  end, FriendList),
					true;

				false -> false
				%stop sending
			end,

After that we check if the message is already in the list. If it's not, we append the message to the message list and keep the reference in a separate list.

case lists:member(MessageRef,MessageRefList) of
				false ->
					NewMessageListRef = [MessageRef | MessageRefList],
					{ok, MessageList} = dict:find(messages, PersonDatabase),
					NewMessageList = [{P,M} | MessageList],
					loop(dict:store(messageRefs,NewMessageListRef,
						 dict:store(messages, NewMessageList, PersonDatabase)));
				true ->
					loop(PersonDatabase)
			end;

Testing

###Usage:

####1. Compile using make

user:shell$ make test

####2. Run the tests

1> tester:test().