%% 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]).
start(Name, Mod) ->
register(Name, spawn(fun() -> loop(Mod, Mod:init()) end)).
start(Name, Mod, State) ->
register(Name, spawn(fun() -> loop(Mod, State) end)).
start_on_node(Node, Mod, State) ->
spawn(Node, fun() -> loop(Mod, State) end).
wait_response(_, Ref) ->
receive
{Ref, crash} -> exit(rpc);
{Ref, ok, Response} -> Response
end.
rpc(Client, Request) ->
Ref = make_ref(),
Client ! {Ref, self(), Request},
wait_response(Client, Ref).
loop(Mod, OldState) ->
receive
{From, Request} ->
try Mod:handle(Request, OldState) of
{Response, NewState} ->
From ! {ok, Response},
loop(Mod, NewState)
catch
_: Why ->
log_the_error(Request, Why),
From ! {crash},
loop(Mod, OldState)
end;
{Ref, From, Request} when is_reference(Ref) ->
try Mod:handle(Request, OldState) of
{Response, NewState} ->
From ! {Ref, ok, Response},
loop(Mod, NewState)
catch
_: Why ->
log_the_error(Request, Why),
From ! {Ref, crash},
loop(Mod, OldState)
end;
{'EXIT', From, Why} ->
try Mod:handle({'EXIT', From, Why}, OldState) of
NewState ->
loop(Mod, NewState)
catch
_: Why ->
log_the_error('EXIT', Why),
loop(Mod, OldState)
end
end.
log_the_error(Request, Why) ->
io:format("Server request ~p ~n"
"caused exception ~p~n",
[Request, Why]).