%% Inspired by "Programming Erlang", %% published by The Pragmatic Bookshelf. %% Copyrights apply to this code. %% We make no guarantees that this code is fit for any purpose. %% Visit http://www.pragmaticprogrammer.com/titles/jaerlang for more book information. -module(server). -export([start/2, start/3, start_on_node/3, rpc/2, send/2, registration/2]). start(Name, Mod) -> register(Name, spawn(fun() -> loop(Name, Mod, Mod:init()) end)). start(Name, Mod, State) -> register(Name, spawn(fun() -> loop(Name, Mod, State) end)). start_on_node(Node, Mod, State) -> Ref = make_ref(), Pid = spawn(Node, fun() -> loop(Ref, Mod, State) end), {Pid, Ref}. send({Client, _}, Data) -> send(Client, Data); send(Client, Data) -> Client ! Data. wait_response({_, Name}) -> wait_response(Name); wait_response(Name) -> receive {Name, crash} -> exit(rpc); {Name, ok, Response} -> Response end. rpc(Client, Request) -> send(Client, {self(), Request}), wait_response(Client). registration(Client, NewName) -> send(Client, {register, NewName}). loop(Name, Mod, OldState) -> receive {register, NewName} -> register(NewName, self()), loop(NewName, Mod, OldState); {From, Request} -> try Mod:handle(Request, OldState) of {Response, NewState} -> From ! {Name, ok, Response}, loop(Name, Mod, NewState) catch _: Why -> log_the_error(Name, Request, Why), From ! {Name, crash}, loop(Name, Mod, OldState) end; {'EXIT', From, Why} -> try Mod:handle({'EXIT', From, Why}, OldState) of NewState -> loop(Name, Mod, NewState) catch _: Why -> log_the_error(From, 'EXIT', Why), loop(Name, Mod, OldState) end end. log_the_error(Name, Request, Why) -> io:format("Server ~p request ~p ~n" "caused exception ~p~n", [Name, Request, Why]).