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