aboutsummaryrefslogtreecommitdiffstats
path: root/common/server.erl
blob: 67fb000d2baea3f68365f1732aff3a66a64c85b9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
%%  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]).