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. |