Skip to content

Instantly share code, notes, and snippets.

@archaelus
Created October 22, 2010 06:36
Show Gist options
  • Save archaelus/640060 to your computer and use it in GitHub Desktop.
Save archaelus/640060 to your computer and use it in GitHub Desktop.
Highlighted paste from http://pastebin.ca/1969638
-module(p2pphonebook).
-export([start/1, add/2, list_all/1, update/2,delete/2,find/2,join/2,join/3,splitContacts/2,updateContactsAndPeers/2]).
%% Interface
start(X) -> spawn(fun() -> loop({dict:new(),{'','',erlang:md5(X),''}}) end).
add(Pid, Contact) ->
rpc(Pid, {add, Contact}).
list_all(Pid) ->
rpc(Pid, list_all).
update(Pid, Contact) ->
rpc(Pid, {update, Contact}).
delete(Pid,Contact) ->
rpc(Pid, {delete, Contact}).
find(Pid,ContactName) ->
rpc(Pid, {find, ContactName}).
join(NewPeerPid, NetworkPid) ->
rpc(NewPeerPid, {initiatejoin, NetworkPid}).
join(NetworkPid,NewPeerId,GUID) ->
rpc(NetworkPid,{join, NewPeerId,GUID}).
updateContactsAndPeers(Pid, PeerInfo) ->
io:format("1 ~p~p~n",[Pid,PeerInfo]),rpc(Pid,{updateInfo, PeerInfo}).
%% Internal implementation
rpc(Pid, Request) ->
io:format("2 ~p~p~p~n",[Pid,self(),Request]), Pid ! {self(), Request},
receive
{Pid, Response} ->
io:format("3 ~p~p~p~n",[self(),Pid,Response]),Response
end.
loop(ContactsAndRoutingInfo) ->
receive
{From, Request} ->
{Res, Updated} = handle_request(Request, ContactsAndRoutingInfo),
io:format("In loop ~p~p~p~p~p~n",[From,self(),Request,Res,Updated]),
From ! {self(), Res},
loop(Updated)
end.
splitContacts(AtGUID, Contacts) ->
ToHigh = fun(Name,_Contact) ->
erlang:md5(Name) >= AtGUID
end,
Higher = dict:filter(ToHigh,Contacts),
Lower = dict:filter(fun(N,C) ->
not ToHigh(N,C) end, Contacts),
{Lower,Higher}.
%%
handle_request(Request, {Contacts,RoutingInfo={LeftPeerId,RightPeerId,LowerGUID,HigherGUID}}) ->
case Request of
{add, Contact} ->
{Name,_,_} = Contact,
NameGUID = erlang:md5(Name),
case NameGUID < LowerGUID of
true when length(LeftPeerId) > 0 ->
add(LeftPeerId,Contact);
false when NameGUID >= HigherGUID , length(RightPeerId) =:= 0 ->
add(RightPeerId,Contact);
_ -> case dict:is_key(Name, Contacts) of
false -> {ok, {dict:store(Name, Contact, Contacts),RoutingInfo}};
true -> {{error, Name, is_already_there},
{Contacts,RoutingInfo}}
end
end;
list_all ->
List = dict:to_list(Contacts),
{{ok, lists:map(fun({_, C}) -> C end, List)},
{Contacts,RoutingInfo}};
{update, Contact} ->
{Name,_,_} = Contact,
NameGUID = erlang:md5(Name),
case NameGUID < LowerGUID of
true when length(LeftPeerId) > 0 ->
update(LeftPeerId,Contact);
false when NameGUID >= HigherGUID , length(RightPeerId) =:= 0 ->
update(RightPeerId,Contact);
_ -> {ok, {dict:store(Name, Contact, Contacts),RoutingInfo}}
end;
{delete, Contact} ->
{Name,_,_} = Contact,
NameGUID = erlang:md5(Name),
case NameGUID < LowerGUID of
true when length(LeftPeerId) > 0 ->
delete(LeftPeerId,Contact);
false when NameGUID >= HigherGUID , length(RightPeerId) =:= 0 ->
delete(RightPeerId,Contact);
_ -> case dict:is_key(Name,Contacts) of
true -> case dict:fetch(Name,Contacts) of
Contact -> {ok, {dict:erase(Name,Contacts),RoutingInfo}};
_ -> {{error, Name, attributes_do_not_match},{Contacts,RoutingInfo}}
end;
false -> {{error, Name, is_not_there},
{Contacts,RoutingInfo}}
end
end;
{find, Name} ->
NameGUID = erlang:md5(Name),
case NameGUID < LowerGUID of
true when length(LeftPeerId) > 0 ->
find(LeftPeerId,Name);
false when NameGUID >= HigherGUID , length(RightPeerId) =:= 0 ->
find(RightPeerId,Name);
_ -> case dict:is_key(Name,Contacts) of
true -> {{ok,dict:fetch(Name,Contacts)},{Contacts,RoutingInfo}};
false -> {{error, Name, is_not_there},{Contacts,RoutingInfo}}
end
end;
{initiatejoin, NetworkPeerId} ->
%io:format("1 abc ~s~s~n",[NetworkPeerId,self()]),
join(NetworkPeerId,self(),LowerGUID);
{join, NewPeerId, NewPeerGUID} ->
%io:format("1 abc ~s~s~s~n",[NewPeerId,NewPeerGUID,self()]),
case NewPeerGUID < LowerGUID of
true when length(LeftPeerId) =:= 0 ; NewPeerGUID < LowerGUID ->
{Lower,Higher} = splitContacts(NewPeerGUID,Contacts),
%updateContactsAndPeers(NewPeerId,{Lower,{LeftPeerId,self(),NewPeerGUID,LowerGUID}}),
io:format("Hee"),
NewPeerId ! {updateInfo,{Lower,{LeftPeerId,self(),NewPeerGUID,LowerGUID}}},
{ok, {Higher,NewPeerId,RightPeerId,LowerGUID,HigherGUID}};
true when length(LeftPeerId) =/= 0 ->
join(LeftPeerId,NewPeerId,NewPeerGUID);
false when length(RightPeerId) =:= 0 ; NewPeerGUID > LowerGUID ->
{Lower,Higher} = splitContacts(NewPeerGUID,Contacts),
%updateContactsAndPeers(NewPeerId,{Higher,{self(),RightPeerId,NewPeerGUID,HigherGUID}}),
io:format("Haa"),
NewPeerId ! {updateInfo,{Higher,{self(),RightPeerId,NewPeerGUID,HigherGUID}}},
{ok, {Lower,LeftPeerId,NewPeerId,LowerGUID,NewPeerGUID}};
false when length(RightPeerId) =/= 0 ->
join(RightPeerId,NewPeerId,NewPeerGUID);
_ ->
{{error,unknown_case},{Contacts,RoutingInfo}}
end;
{updateInfo, PeerInfo} ->
io:format("M ~n",[]),
{Contact,{NewLeftPeerId,NewRightPeerId,NewLowerGUID,NewHigherGUID}} = PeerInfo,
{ok, {Contact,{NewLeftPeerId,NewRightPeerId,NewLowerGUID,NewHigherGUID}}};
Other ->
{{error,unknown_request, Other},
{Contacts,RoutingInfo}}
end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment