| David Reiss | ac54955 | 2008-06-10 22:56:59 +0000 | [diff] [blame] | 1 | %%%------------------------------------------------------------------- | 
|  | 2 | %%% File    : thrift_server.erl | 
|  | 3 | %%% Author  :  <todd@lipcon.org> | 
|  | 4 | %%% Description : | 
|  | 5 | %%% | 
|  | 6 | %%% Created : 28 Jan 2008 by  <todd@lipcon.org> | 
|  | 7 | %%%------------------------------------------------------------------- | 
|  | 8 | -module(thrift_server). | 
|  | 9 |  | 
|  | 10 | -behaviour(gen_server). | 
|  | 11 |  | 
|  | 12 | %% API | 
|  | 13 | -export([start_link/3]). | 
|  | 14 |  | 
|  | 15 | %% gen_server callbacks | 
|  | 16 | -export([init/1, handle_call/3, handle_cast/2, handle_info/2, | 
|  | 17 | terminate/2, code_change/3]). | 
|  | 18 |  | 
|  | 19 | -define(SERVER, ?MODULE). | 
|  | 20 |  | 
|  | 21 | -record(state, {listen_socket, acceptor, service}). | 
|  | 22 | -record(handler, {module}). | 
|  | 23 |  | 
|  | 24 | %%==================================================================== | 
|  | 25 | %% API | 
|  | 26 | %%==================================================================== | 
|  | 27 | %%-------------------------------------------------------------------- | 
|  | 28 | %% Function: start_link() -> {ok,Pid} | ignore | {error,Error} | 
|  | 29 | %% Description: Starts the server | 
|  | 30 | %%-------------------------------------------------------------------- | 
|  | 31 | start_link(Port, Service, HandlerModule) when is_integer(Port), is_atom(HandlerModule) -> | 
|  | 32 | gen_server:start_link({local, ?SERVER}, ?MODULE, {Port, Service, HandlerModule}, []). | 
|  | 33 |  | 
|  | 34 | %%==================================================================== | 
|  | 35 | %% gen_server callbacks | 
|  | 36 | %%==================================================================== | 
|  | 37 |  | 
|  | 38 | %%-------------------------------------------------------------------- | 
|  | 39 | %% Function: init(Args) -> {ok, State} | | 
|  | 40 | %%                         {ok, State, Timeout} | | 
|  | 41 | %%                         ignore               | | 
|  | 42 | %%                         {stop, Reason} | 
|  | 43 | %% Description: Initiates the server | 
|  | 44 | %%-------------------------------------------------------------------- | 
|  | 45 | init({Port, Service, HandlerModule}) -> | 
|  | 46 | Handler = #handler{module = HandlerModule}, | 
|  | 47 | {ok, Socket} = gen_tcp:listen(Port, | 
|  | 48 | [binary, | 
|  | 49 | {packet, 0}, | 
|  | 50 | {active, false}, | 
|  | 51 | {nodelay, true}, | 
|  | 52 | {reuseaddr, true}]), | 
|  | 53 | Acceptor = spawn_link(fun () -> acceptor(Socket, Service, Handler) end), | 
|  | 54 | {ok, #state{listen_socket = Socket, | 
|  | 55 | acceptor = Acceptor, | 
|  | 56 | service = Service}}. | 
|  | 57 |  | 
|  | 58 | %%-------------------------------------------------------------------- | 
|  | 59 | %% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} | | 
|  | 60 | %%                                      {reply, Reply, State, Timeout} | | 
|  | 61 | %%                                      {noreply, State} | | 
|  | 62 | %%                                      {noreply, State, Timeout} | | 
|  | 63 | %%                                      {stop, Reason, Reply, State} | | 
|  | 64 | %%                                      {stop, Reason, State} | 
|  | 65 | %% Description: Handling call messages | 
|  | 66 | %%-------------------------------------------------------------------- | 
|  | 67 | handle_call(_Request, _From, State) -> | 
|  | 68 | Reply = ok, | 
|  | 69 | {reply, Reply, State}. | 
|  | 70 |  | 
|  | 71 | %%-------------------------------------------------------------------- | 
|  | 72 | %% Function: handle_cast(Msg, State) -> {noreply, State} | | 
|  | 73 | %%                                      {noreply, State, Timeout} | | 
|  | 74 | %%                                      {stop, Reason, State} | 
|  | 75 | %% Description: Handling cast messages | 
|  | 76 | %%-------------------------------------------------------------------- | 
|  | 77 | handle_cast(_Msg, State) -> | 
|  | 78 | {noreply, State}. | 
|  | 79 |  | 
|  | 80 | %%-------------------------------------------------------------------- | 
|  | 81 | %% Function: handle_info(Info, State) -> {noreply, State} | | 
|  | 82 | %%                                       {noreply, State, Timeout} | | 
|  | 83 | %%                                       {stop, Reason, State} | 
|  | 84 | %% Description: Handling all non call/cast messages | 
|  | 85 | %%-------------------------------------------------------------------- | 
|  | 86 | handle_info(_Info, State) -> | 
|  | 87 | {noreply, State}. | 
|  | 88 |  | 
|  | 89 | %%-------------------------------------------------------------------- | 
|  | 90 | %% Function: terminate(Reason, State) -> void() | 
|  | 91 | %% Description: This function is called by a gen_server when it is about to | 
|  | 92 | %% terminate. It should be the opposite of Module:init/1 and do any necessary | 
|  | 93 | %% cleaning up. When it returns, the gen_server terminates with Reason. | 
|  | 94 | %% The return value is ignored. | 
|  | 95 | %%-------------------------------------------------------------------- | 
|  | 96 | terminate(_Reason, _State) -> | 
|  | 97 | ok. | 
|  | 98 |  | 
|  | 99 | %%-------------------------------------------------------------------- | 
|  | 100 | %% Func: code_change(OldVsn, State, Extra) -> {ok, NewState} | 
|  | 101 | %% Description: Convert process state when code is changed | 
|  | 102 | %%-------------------------------------------------------------------- | 
|  | 103 | code_change(_OldVsn, State, _Extra) -> | 
|  | 104 | State#state.acceptor ! refresh, | 
|  | 105 | {ok, State}. | 
|  | 106 |  | 
|  | 107 | %%-------------------------------------------------------------------- | 
|  | 108 | %%% Internal functions | 
|  | 109 | %%-------------------------------------------------------------------- | 
|  | 110 |  | 
|  | 111 | acceptor(ListenSocket, Service, Handler) | 
|  | 112 | when is_port(ListenSocket), is_record(Handler, handler) -> | 
|  | 113 | {ok, Socket} = gen_tcp:accept(ListenSocket), | 
|  | 114 | error_logger:info_msg("Accepted client"), | 
|  | 115 |  | 
|  | 116 | {ok, Transport} = thrift_socket_transport:new(Socket), | 
|  | 117 | {ok, Protocol} = thrift_binary_protocol:new(Transport), | 
|  | 118 |  | 
|  | 119 | thrift_processor:start(Protocol, Protocol, Service, Handler), | 
|  | 120 | receive | 
|  | 121 | refresh -> | 
|  | 122 | error_logger:info_msg("Acceptor refreshing~n"), | 
|  | 123 | ?MODULE:acceptor(ListenSocket, Service, Handler) | 
|  | 124 | after 0      -> acceptor(ListenSocket, Service, Handler) | 
|  | 125 | end. |