Browse files

Initial code commit

  • Loading branch information...
0 parents commit 6c067729cb858e6b93d5ffb670c0cea24e4f2522 @ericbmerritt committed Sep 22, 2011
Showing with 297 additions and 0 deletions.
  1. +35 −0 ex1.erl
  2. +29 −0 ex2.erl
  3. +52 −0 ex2behaviour.erl
  4. +12 −0 tcp_rpc/ebin/tcp_rpc.app
  5. +25 −0 tcp_rpc/src/tr_app.erl
  6. +119 −0 tcp_rpc/src/tr_server.erl
  7. +25 −0 tcp_rpc/src/tr_sup.erl
35 ex1.erl
@@ -0,0 +1,35 @@
+-module(ex1).
+
+-export([start/0, store/2, stop/0]).
+
+%%% API
+
+start() ->
+ spawn(fun() -> init() end).
+
+store(Key, Value) ->
+ ex1 ! {store, {Key, Value}}.
+
+stop() ->
+ ex1 ! stop.
+
+%%% Internal Functions
+
+init() ->
+ register(ex1, self()),
+ io:format("process starting~n"),
+ loop([]).
+
+loop(State) ->
+ receive
+ {store, {Key, _Value} = Data} ->
+ io:format("storing ~p~n", [Key]),
+ loop([Data|State]);
+ stop ->
+ io:format("stopping process ~p with state ~p~n", [self(), State]),
+ ok;
+ BadMsg ->
+ io:format("bad message ~p~n", [BadMsg]),
+ exit(BadMsg)
+ end.
+
29 ex2.erl
@@ -0,0 +1,29 @@
+-module(ex2).
+
+-export([start/0, store/2, stop/0]).
+
+-export([init/0, handle_msg/2]).
+
+%%% API
+
+start() ->
+ ex2behaviour:start(?MODULE).
+
+store(Key, Value) ->
+ ex2behaviour:send(ex2, {store, {Key, Value}}).
+
+stop() ->
+ ex2behaviour:send(ex2, stop).
+
+%%% Internal Functions
+
+init() ->
+ register(ex2, self()),
+ {ok, []}.
+
+handle_msg({store, {Key, _Value} = Data}, State) ->
+ io:format("storing ~p~n", [Key]),
+ {ok, [Data|State]};
+handle_msg(stop, State) ->
+ io:format("stopping process ~p with state ~p~n", [self(), State]),
+ {stop, State}.
52 ex2behaviour.erl
@@ -0,0 +1,52 @@
+-module(ex2behaviour).
+
+-export([start/1, send/2]).
+-export([init/2, behaviour_info/1]).
+
+start(CallBack) ->
+ proc_lib:start_link(?MODULE, init, [self(), CallBack]).
+
+send(Pid, Msg) ->
+ Pid ! {'$ex2behaviour', send, Msg}.
+
+
+%%% Internal functions
+
+init(Parent, CallBack) ->
+ try
+ {ok, State} = CallBack:init(),
+ proc_lib:init_ack(Parent, {ok, self()}),
+ loop(CallBack, State)
+ catch
+ _C:E ->
+ io:format("going down with ~p~n", [E]),
+ exit(E)
+ end.
+
+behaviour_info(callbacks) ->
+ [{init, 0},
+ {handle_msg, 2}];
+behaviour_info(_) ->
+ undefined.
+
+loop(CallBack, State) ->
+ receive
+ {'$ex2behaviour', send, Msg} ->
+ case catch CallBack:handle_msg(Msg, State) of
+ {ok, NewState} ->
+ loop(CallBack, NewState);
+ {stop, NewState} ->
+ io:format("stopping process ~p with state ~p~n", [self(), NewState]),
+ ok;
+ Error ->
+ io:format("application error ~p~n", [Error]),
+ exit(Error)
+ end;
+ BadMsg ->
+ io:format("bad message ~p~n", [BadMsg]),
+ exit(BadMsg)
+ end.
+
+
+
+
12 tcp_rpc/ebin/tcp_rpc.app
@@ -0,0 +1,12 @@
+%% -*- mode: Erlang; fill-column: 75; comment-column: 50; -*-
+
+{application, tcp_rpc,
+ [{description, "RPC server for Erlang and OTP in action"},
+ {vsn, "0.1.0"},
+ {modules, [tr_app,
+ tr_sup,
+ tr_server]},
+ {registered, [tr_sup]},
+ {applications, [kernel, stdlib]},
+ {mod, {tr_app, []}}
+ ]}.
25 tcp_rpc/src/tr_app.erl
@@ -0,0 +1,25 @@
+x-module(tr_app).
+
+-behaviour(application).
+
+-export([
+ start/2,
+ stop/1
+ ]).
+
+-define(DEFAULT_PORT, 8080).
+
+start(_Type, _StartArgs) ->
+ {ok, LSock} = gen_tcp:listen(?DEFAULT_PORT,
+ [{reuseaddr, true}, {active, true}]),
+
+ case tr_sup:start_link(LSock) of
+ {ok, Pid} ->
+ tr_sup:start_child(),
+ {ok, Pid};
+ Error ->
+ Error
+ end.
+
+stop(_State) ->
+ ok.
119 tcp_rpc/src/tr_server.erl
@@ -0,0 +1,119 @@
+%%%-------------------------------------------------------------------
+%%% @author Martin & Eric <erlware-dev@googlegroups.com>
+%%% [http://www.erlware.org]
+%%% @copyright 2008-2010 Erlware
+%%% @doc RPC over TCP server. This module defines a server process that
+%%% listens for incoming TCP connections and allows the user to
+%%% execute RPC commands via that TCP stream.
+%%% @end
+%%%-------------------------------------------------------------------
+
+-module(tr_server).
+
+-behaviour(gen_server).
+
+%% API
+-export([
+ start_link/1,
+ get_count/0,
+ stop/0
+ ]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+-define(SERVER, ?MODULE).
+
+-record(state, {lsock, request_count = 0}).
+
+
+%%%===================================================================
+%%% API
+%%%===================================================================
+
+
+%%--------------------------------------------------------------------
+%% @doc Starts the server.
+%%
+%% @spec start_link(LSock::term()) -> {ok, Pid}
+%% where
+%% Pid = pid()
+%% @end
+%%--------------------------------------------------------------------
+start_link(LSock) ->
+ gen_server:start_link(?MODULE, [LSock], []).
+
+%%--------------------------------------------------------------------
+%% @doc Fetches the number of requests made to this server.
+%% @spec get_count() -> {ok, Count}
+%% where
+%% Count = integer()
+%% @end
+%%--------------------------------------------------------------------
+get_count() ->
+ gen_server:call(?SERVER, get_count).
+
+%%--------------------------------------------------------------------
+%% @doc Stops the server.
+%% @spec stop() -> ok
+%% @end
+%%--------------------------------------------------------------------
+stop() ->
+ gen_server:cast(?SERVER, stop).
+
+
+%%%===================================================================
+%%% gen_server callbacks
+%%%===================================================================
+
+init([LSock]) ->
+ {ok, #state{lsock = LSock}, 0}.
+
+handle_call(get_count, _From, State) ->
+ {reply, {ok, State#state.request_count}, State}.
+
+handle_cast(stop, State) ->
+ {stop, normal, State}.
+
+handle_info({tcp, Socket, RawData}, State) ->
+ do_rpc(Socket, RawData),
+ RequestCount = State#state.request_count,
+ {noreply, State#state{request_count = RequestCount + 1}};
+handle_info(timeout, #state{lsock = LSock} = State) ->
+ {ok, _Sock} = gen_tcp:accept(LSock),
+ 
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
+
+do_rpc(Socket, RawData) ->
+ try
+ {M, F, A} = split_out_mfa(RawData),
+ Result = apply(M, F, A),
+ gen_tcp:send(Socket, io_lib:fwrite("~p~n", [Result]))
+ catch
+ _Class:Err ->
+ gen_tcp:send(Socket, io_lib:fwrite("~p~n", [Err]))
+ end.
+
+split_out_mfa(RawData) ->
+ MFA = re:replace(RawData, "\r\n$", "", [{return, list}]),
+ {match, [M, F, A]} =
+ re:run(MFA,
+ "(.*):(.*)\s*\\((.*)\s*\\)\s*.\s*$",
+ [{capture, [1,2,3], list}, ungreedy]),
+ {list_to_atom(M), list_to_atom(F), args_to_terms(A)}.
+
+args_to_terms(RawArgs) ->
+ {ok, Toks, _Line} = erl_scan:string("[" ++ RawArgs ++ "]. ", 1),
+ {ok, Args} = erl_parse:parse_term(Toks),
+ Args.
25 tcp_rpc/src/tr_sup.erl
@@ -0,0 +1,25 @@
+-module(tr_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/1, start_child/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+-define(SERVER, ?MODULE).
+
+start_link(LSock) ->
+ supervisor:start_link({local, ?SERVER}, ?MODULE, [LSock]).
+
+start_child() ->
+ supervisor:start_child(?SERVER, []).
+
+init([LSock]) ->
+ Server = {tr_server, {tr_server, start_link, [LSock]},
+ temporary, 2000, worker, [tr_server]},
+
+ Children = [Server],
+ RestartStrategy = {simple_one_for_one, 0, 1},
+ {ok, {RestartStrategy, Children}}.

0 comments on commit 6c06772

Please sign in to comment.