David Reiss | ea2cba8 | 2009-03-30 21:35:00 +0000 | [diff] [blame] | 1 | %% |
| 2 | %% Licensed to the Apache Software Foundation (ASF) under one |
| 3 | %% or more contributor license agreements. See the NOTICE file |
| 4 | %% distributed with this work for additional information |
| 5 | %% regarding copyright ownership. The ASF licenses this file |
| 6 | %% to you under the Apache License, Version 2.0 (the |
| 7 | %% "License"); you may not use this file except in compliance |
| 8 | %% with the License. You may obtain a copy of the License at |
| 9 | %% |
| 10 | %% http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | %% |
| 12 | %% Unless required by applicable law or agreed to in writing, |
| 13 | %% software distributed under the License is distributed on an |
| 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 15 | %% KIND, either express or implied. See the License for the |
| 16 | %% specific language governing permissions and limitations |
| 17 | %% under the License. |
| 18 | %% |
| 19 | |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 20 | -module(thrift_client). |
| 21 | |
| 22 | -behaviour(gen_server). |
| 23 | |
| 24 | %% API |
David Reiss | 5e530af | 2009-06-04 02:01:24 +0000 | [diff] [blame] | 25 | -export([start_link/2, start_link/3, start_link/4, |
| 26 | start/3, start/4, |
| 27 | call/3, send_call/3, close/1]). |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 28 | |
| 29 | %% gen_server callbacks |
| 30 | -export([init/1, handle_call/3, handle_cast/2, handle_info/2, |
| 31 | terminate/2, code_change/3]). |
| 32 | |
| 33 | |
| 34 | -include("thrift_constants.hrl"). |
| 35 | -include("thrift_protocol.hrl"). |
| 36 | |
David Reiss | ad74b32 | 2008-06-11 01:03:29 +0000 | [diff] [blame] | 37 | -record(state, {service, protocol, seqid}). |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 38 | |
| 39 | %%==================================================================== |
| 40 | %% API |
| 41 | %%==================================================================== |
| 42 | %%-------------------------------------------------------------------- |
| 43 | %% Function: start_link() -> {ok,Pid} | ignore | {error,Error} |
David Reiss | 5e530af | 2009-06-04 02:01:24 +0000 | [diff] [blame] | 44 | %% Description: Starts the server as a linked process. |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 45 | %%-------------------------------------------------------------------- |
David Reiss | ad74b32 | 2008-06-11 01:03:29 +0000 | [diff] [blame] | 46 | start_link(Host, Port, Service) when is_integer(Port), is_atom(Service) -> |
David Reiss | 914ebb4 | 2008-06-11 01:01:48 +0000 | [diff] [blame] | 47 | start_link(Host, Port, Service, []). |
David Reiss | 4fd7818 | 2008-06-11 01:01:13 +0000 | [diff] [blame] | 48 | |
David Reiss | 5e530af | 2009-06-04 02:01:24 +0000 | [diff] [blame] | 49 | start_link(Host, Port, Service, Options) -> |
| 50 | start(Host, Port, Service, [{monitor, link} | Options]). |
| 51 | |
| 52 | start_link(ProtocolFactory, Service) -> |
| 53 | start(ProtocolFactory, Service, [{monitor, link}]). |
David Reiss | fc427af | 2008-06-11 01:11:57 +0000 | [diff] [blame] | 54 | |
| 55 | %% |
| 56 | %% Splits client options into protocol options and transport options |
| 57 | %% |
| 58 | %% split_options([Options...]) -> {ProtocolOptions, TransportOptions} |
| 59 | %% |
| 60 | split_options(Options) -> |
David Reiss | 5e530af | 2009-06-04 02:01:24 +0000 | [diff] [blame] | 61 | split_options(Options, [], [], []). |
David Reiss | fc427af | 2008-06-11 01:11:57 +0000 | [diff] [blame] | 62 | |
David Reiss | 5e530af | 2009-06-04 02:01:24 +0000 | [diff] [blame] | 63 | split_options([], ClientIn, ProtoIn, TransIn) -> |
| 64 | {ClientIn, ProtoIn, TransIn}; |
David Reiss | fc427af | 2008-06-11 01:11:57 +0000 | [diff] [blame] | 65 | |
David Reiss | 5e530af | 2009-06-04 02:01:24 +0000 | [diff] [blame] | 66 | split_options([Opt = {OptKey, _} | Rest], ClientIn, ProtoIn, TransIn) |
| 67 | when OptKey =:= monitor -> |
| 68 | split_options(Rest, [Opt | ClientIn], ProtoIn, TransIn); |
| 69 | |
| 70 | split_options([Opt = {OptKey, _} | Rest], ClientIn, ProtoIn, TransIn) |
David Reiss | fc427af | 2008-06-11 01:11:57 +0000 | [diff] [blame] | 71 | when OptKey =:= strict_read; |
| 72 | OptKey =:= strict_write -> |
David Reiss | 5e530af | 2009-06-04 02:01:24 +0000 | [diff] [blame] | 73 | split_options(Rest, ClientIn, [Opt | ProtoIn], TransIn); |
David Reiss | fc427af | 2008-06-11 01:11:57 +0000 | [diff] [blame] | 74 | |
David Reiss | 5e530af | 2009-06-04 02:01:24 +0000 | [diff] [blame] | 75 | split_options([Opt = {OptKey, _} | Rest], ClientIn, ProtoIn, TransIn) |
David Reiss | fc427af | 2008-06-11 01:11:57 +0000 | [diff] [blame] | 76 | when OptKey =:= framed; |
| 77 | OptKey =:= connect_timeout; |
| 78 | OptKey =:= sockopts -> |
David Reiss | 5e530af | 2009-06-04 02:01:24 +0000 | [diff] [blame] | 79 | split_options(Rest, ClientIn, ProtoIn, [Opt | TransIn]). |
David Reiss | fc427af | 2008-06-11 01:11:57 +0000 | [diff] [blame] | 80 | |
| 81 | |
David Reiss | 5e530af | 2009-06-04 02:01:24 +0000 | [diff] [blame] | 82 | %%-------------------------------------------------------------------- |
| 83 | %% Function: start() -> {ok,Pid} | ignore | {error,Error} |
| 84 | %% Description: Starts the server as an unlinked process. |
| 85 | %%-------------------------------------------------------------------- |
| 86 | |
David Reiss | fc427af | 2008-06-11 01:11:57 +0000 | [diff] [blame] | 87 | %% Backwards-compatible starter for the common-case of socket transports |
David Reiss | 5e530af | 2009-06-04 02:01:24 +0000 | [diff] [blame] | 88 | start(Host, Port, Service, Options) |
David Reiss | 2fe905e | 2008-06-11 01:02:23 +0000 | [diff] [blame] | 89 | when is_integer(Port), is_atom(Service), is_list(Options) -> |
David Reiss | 5e530af | 2009-06-04 02:01:24 +0000 | [diff] [blame] | 90 | {ClientOpts, ProtoOpts, TransOpts} = split_options(Options), |
David Reiss | fc427af | 2008-06-11 01:11:57 +0000 | [diff] [blame] | 91 | |
| 92 | {ok, TransportFactory} = |
| 93 | thrift_socket_transport:new_transport_factory(Host, Port, TransOpts), |
| 94 | |
| 95 | {ok, ProtocolFactory} = thrift_binary_protocol:new_protocol_factory( |
| 96 | TransportFactory, ProtoOpts), |
| 97 | |
David Reiss | 5e530af | 2009-06-04 02:01:24 +0000 | [diff] [blame] | 98 | start(ProtocolFactory, Service, ClientOpts). |
David Reiss | ad74b32 | 2008-06-11 01:03:29 +0000 | [diff] [blame] | 99 | |
David Reiss | fc427af | 2008-06-11 01:11:57 +0000 | [diff] [blame] | 100 | |
David Reiss | 44f785e | 2008-06-11 01:03:37 +0000 | [diff] [blame] | 101 | %% ProtocolFactory :: fun() -> thrift_protocol() |
David Reiss | 5e530af | 2009-06-04 02:01:24 +0000 | [diff] [blame] | 102 | start(ProtocolFactory, Service, ClientOpts) |
David Reiss | 44f785e | 2008-06-11 01:03:37 +0000 | [diff] [blame] | 103 | when is_function(ProtocolFactory), is_atom(Service) -> |
David Reiss | 1e1a697 | 2009-06-04 02:01:32 +0000 | [diff] [blame] | 104 | {Starter, Opts} = |
David Reiss | 5e530af | 2009-06-04 02:01:24 +0000 | [diff] [blame] | 105 | case lists:keysearch(monitor, 1, ClientOpts) of |
| 106 | {value, {monitor, link}} -> |
David Reiss | 1e1a697 | 2009-06-04 02:01:32 +0000 | [diff] [blame] | 107 | {start_link, []}; |
| 108 | {value, {monitor, tether}} -> |
| 109 | {start, [{tether, self()}]}; |
David Reiss | 5e530af | 2009-06-04 02:01:24 +0000 | [diff] [blame] | 110 | _ -> |
David Reiss | 1e1a697 | 2009-06-04 02:01:32 +0000 | [diff] [blame] | 111 | {start, []} |
David Reiss | 5e530af | 2009-06-04 02:01:24 +0000 | [diff] [blame] | 112 | end, |
| 113 | |
David Reiss | bb97fd9 | 2009-06-04 02:01:28 +0000 | [diff] [blame] | 114 | Connect = |
| 115 | case lists:keysearch(connect, 1, ClientOpts) of |
| 116 | {value, {connect, Choice}} -> |
| 117 | Choice; |
| 118 | _ -> |
| 119 | %% By default, connect at creation-time. |
| 120 | true |
| 121 | end, |
| 122 | |
| 123 | |
David Reiss | 1e1a697 | 2009-06-04 02:01:32 +0000 | [diff] [blame] | 124 | Started = gen_server:Starter(?MODULE, [Service, Opts], []), |
David Reiss | bb97fd9 | 2009-06-04 02:01:28 +0000 | [diff] [blame] | 125 | |
| 126 | if |
| 127 | Connect -> |
| 128 | case Started of |
| 129 | {ok, Pid} -> |
| 130 | case gen_server:call(Pid, {connect, ProtocolFactory}) of |
| 131 | ok -> |
| 132 | {ok, Pid}; |
| 133 | Error -> |
| 134 | Error |
| 135 | end; |
| 136 | Else -> |
| 137 | Else |
David Reiss | e5a4d0c | 2008-06-11 01:02:10 +0000 | [diff] [blame] | 138 | end; |
David Reiss | bb97fd9 | 2009-06-04 02:01:28 +0000 | [diff] [blame] | 139 | true -> |
| 140 | Started |
David Reiss | e5a4d0c | 2008-06-11 01:02:10 +0000 | [diff] [blame] | 141 | end. |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 142 | |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 143 | call(Client, Function, Args) |
| 144 | when is_pid(Client), is_atom(Function), is_list(Args) -> |
| 145 | case gen_server:call(Client, {call, Function, Args}) of |
| 146 | R = {ok, _} -> R; |
| 147 | R = {error, _} -> R; |
| 148 | {exception, Exception} -> throw(Exception) |
| 149 | end. |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 150 | |
David Reiss | a2f4597 | 2008-06-11 01:13:33 +0000 | [diff] [blame] | 151 | cast(Client, Function, Args) |
| 152 | when is_pid(Client), is_atom(Function), is_list(Args) -> |
| 153 | gen_server:cast(Client, {call, Function, Args}). |
| 154 | |
David Reiss | 65cf720 | 2008-06-11 01:12:20 +0000 | [diff] [blame] | 155 | %% Sends a function call but does not read the result. This is useful |
David Reiss | c51986f | 2009-03-24 20:01:25 +0000 | [diff] [blame] | 156 | %% if you're trying to log non-oneway function calls to write-only |
David Reiss | 65cf720 | 2008-06-11 01:12:20 +0000 | [diff] [blame] | 157 | %% transports like thrift_disk_log_transport. |
| 158 | send_call(Client, Function, Args) |
| 159 | when is_pid(Client), is_atom(Function), is_list(Args) -> |
| 160 | gen_server:call(Client, {send_call, Function, Args}). |
| 161 | |
David Reiss | 464e300 | 2008-06-11 01:00:45 +0000 | [diff] [blame] | 162 | close(Client) when is_pid(Client) -> |
David Reiss | 6f1cd53 | 2008-06-11 01:01:21 +0000 | [diff] [blame] | 163 | gen_server:cast(Client, close). |
David Reiss | 464e300 | 2008-06-11 01:00:45 +0000 | [diff] [blame] | 164 | |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 165 | %%==================================================================== |
| 166 | %% gen_server callbacks |
| 167 | %%==================================================================== |
| 168 | |
| 169 | %%-------------------------------------------------------------------- |
| 170 | %% Function: init(Args) -> {ok, State} | |
| 171 | %% {ok, State, Timeout} | |
| 172 | %% ignore | |
| 173 | %% {stop, Reason} |
| 174 | %% Description: Initiates the server |
| 175 | %%-------------------------------------------------------------------- |
David Reiss | 1e1a697 | 2009-06-04 02:01:32 +0000 | [diff] [blame] | 176 | init([Service, Opts]) -> |
| 177 | case lists:keysearch(tether, 1, Opts) of |
| 178 | {value, {tether, Pid}} -> |
| 179 | erlang:monitor(process, Pid); |
| 180 | _Else -> |
| 181 | ok |
| 182 | end, |
David Reiss | ad74b32 | 2008-06-11 01:03:29 +0000 | [diff] [blame] | 183 | {ok, #state{service = Service}}. |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 184 | |
| 185 | %%-------------------------------------------------------------------- |
| 186 | %% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} | |
| 187 | %% {reply, Reply, State, Timeout} | |
| 188 | %% {noreply, State} | |
| 189 | %% {noreply, State, Timeout} | |
| 190 | %% {stop, Reason, Reply, State} | |
| 191 | %% {stop, Reason, State} |
| 192 | %% Description: Handling call messages |
| 193 | %%-------------------------------------------------------------------- |
David Reiss | 44f785e | 2008-06-11 01:03:37 +0000 | [diff] [blame] | 194 | handle_call({connect, ProtocolFactory}, _From, |
David Reiss | ad74b32 | 2008-06-11 01:03:29 +0000 | [diff] [blame] | 195 | State = #state{service = Service}) -> |
David Reiss | 44f785e | 2008-06-11 01:03:37 +0000 | [diff] [blame] | 196 | case ProtocolFactory() of |
David Reiss | ad74b32 | 2008-06-11 01:03:29 +0000 | [diff] [blame] | 197 | {ok, Protocol} -> |
| 198 | {reply, ok, State#state{protocol = Protocol, |
| 199 | seqid = 0}}; |
David Reiss | e5a4d0c | 2008-06-11 01:02:10 +0000 | [diff] [blame] | 200 | Error -> |
| 201 | {stop, normal, Error, State} |
| 202 | end; |
| 203 | |
David Reiss | 65cf720 | 2008-06-11 01:12:20 +0000 | [diff] [blame] | 204 | handle_call({call, Function, Args}, _From, State = #state{service = Service}) -> |
| 205 | Result = catch_function_exceptions( |
| 206 | fun() -> |
| 207 | ok = send_function_call(State, Function, Args), |
| 208 | receive_function_result(State, Function) |
| 209 | end, |
| 210 | Service), |
| 211 | {reply, Result, State}; |
David Reiss | 6b3e40f | 2008-06-11 00:59:03 +0000 | [diff] [blame] | 212 | |
David Reiss | 65cf720 | 2008-06-11 01:12:20 +0000 | [diff] [blame] | 213 | |
| 214 | handle_call({send_call, Function, Args}, _From, State = #state{service = Service}) -> |
| 215 | Result = catch_function_exceptions( |
| 216 | fun() -> |
| 217 | send_function_call(State, Function, Args) |
| 218 | end, |
| 219 | Service), |
David Reiss | 6f1cd53 | 2008-06-11 01:01:21 +0000 | [diff] [blame] | 220 | {reply, Result, State}. |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 221 | |
David Reiss | 65cf720 | 2008-06-11 01:12:20 +0000 | [diff] [blame] | 222 | |
| 223 | %% Helper function that catches exceptions thrown by sending or receiving |
| 224 | %% a function and returns the correct response for call or send_only above. |
| 225 | catch_function_exceptions(Fun, Service) -> |
| 226 | try |
| 227 | Fun() |
| 228 | catch |
| 229 | throw:{return, Return} -> |
| 230 | Return; |
| 231 | error:function_clause -> |
| 232 | ST = erlang:get_stacktrace(), |
| 233 | case hd(ST) of |
| 234 | {Service, function_info, [Function, _]} -> |
| 235 | {error, {no_function, Function}}; |
| 236 | _ -> throw({error, {function_clause, ST}}) |
| 237 | end |
| 238 | end. |
| 239 | |
| 240 | |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 241 | %%-------------------------------------------------------------------- |
| 242 | %% Function: handle_cast(Msg, State) -> {noreply, State} | |
| 243 | %% {noreply, State, Timeout} | |
| 244 | %% {stop, Reason, State} |
| 245 | %% Description: Handling cast messages |
| 246 | %%-------------------------------------------------------------------- |
David Reiss | a2f4597 | 2008-06-11 01:13:33 +0000 | [diff] [blame] | 247 | handle_cast({call, Function, Args}, State = #state{service = Service, |
| 248 | protocol = Protocol, |
| 249 | seqid = SeqId}) -> |
| 250 | _Result = |
| 251 | try |
| 252 | ok = send_function_call(State, Function, Args), |
| 253 | receive_function_result(State, Function) |
| 254 | catch |
| 255 | Class:Reason -> |
| 256 | error_logger:error_msg("error ignored in handle_cast({cast,...},...): ~p:~p~n", [Class, Reason]) |
| 257 | end, |
| 258 | |
| 259 | {noreply, State}; |
| 260 | |
David Reiss | 6f1cd53 | 2008-06-11 01:01:21 +0000 | [diff] [blame] | 261 | handle_cast(close, State=#state{protocol = Protocol}) -> |
| 262 | %% error_logger:info_msg("thrift_client ~p received close", [self()]), |
| 263 | {stop,normal,State}; |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 264 | handle_cast(_Msg, State) -> |
| 265 | {noreply, State}. |
| 266 | |
| 267 | %%-------------------------------------------------------------------- |
| 268 | %% Function: handle_info(Info, State) -> {noreply, State} | |
| 269 | %% {noreply, State, Timeout} | |
| 270 | %% {stop, Reason, State} |
| 271 | %% Description: Handling all non call/cast messages |
| 272 | %%-------------------------------------------------------------------- |
David Reiss | 1e1a697 | 2009-06-04 02:01:32 +0000 | [diff] [blame] | 273 | handle_info({'DOWN', MonitorRef, process, Pid, _Info}, State) |
| 274 | when is_reference(MonitorRef), is_pid(Pid) -> |
| 275 | %% We don't actually verify the correctness of the DOWN message. |
| 276 | {stop, parent_died, State}; |
| 277 | |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 278 | handle_info(_Info, State) -> |
| 279 | {noreply, State}. |
| 280 | |
| 281 | %%-------------------------------------------------------------------- |
| 282 | %% Function: terminate(Reason, State) -> void() |
| 283 | %% Description: This function is called by a gen_server when it is about to |
| 284 | %% terminate. It should be the opposite of Module:init/1 and do any necessary |
| 285 | %% cleaning up. When it returns, the gen_server terminates with Reason. |
| 286 | %% The return value is ignored. |
| 287 | %%-------------------------------------------------------------------- |
David Reiss | e5a4d0c | 2008-06-11 01:02:10 +0000 | [diff] [blame] | 288 | terminate(Reason, State = #state{protocol=undefined}) -> |
| 289 | ok; |
| 290 | terminate(Reason, State = #state{protocol=Protocol}) -> |
David Reiss | 464e300 | 2008-06-11 01:00:45 +0000 | [diff] [blame] | 291 | thrift_protocol:close_transport(Protocol), |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 292 | ok. |
| 293 | |
| 294 | %%-------------------------------------------------------------------- |
| 295 | %% Func: code_change(OldVsn, State, Extra) -> {ok, NewState} |
| 296 | %% Description: Convert process state when code is changed |
| 297 | %%-------------------------------------------------------------------- |
| 298 | code_change(_OldVsn, State, _Extra) -> |
| 299 | {ok, State}. |
| 300 | |
| 301 | %%-------------------------------------------------------------------- |
| 302 | %%% Internal functions |
| 303 | %%-------------------------------------------------------------------- |
| 304 | send_function_call(#state{protocol = Proto, |
| 305 | service = Service, |
| 306 | seqid = SeqId}, |
| 307 | Function, |
| 308 | Args) -> |
| 309 | Params = Service:function_info(Function, params_type), |
| 310 | {struct, PList} = Params, |
David Reiss | c525745 | 2008-06-11 00:59:27 +0000 | [diff] [blame] | 311 | if |
| 312 | length(PList) =/= length(Args) -> |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 313 | throw({return, {error, {bad_args, Function, Args}}}); |
David Reiss | c525745 | 2008-06-11 00:59:27 +0000 | [diff] [blame] | 314 | true -> ok |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 315 | end, |
| 316 | |
| 317 | Begin = #protocol_message_begin{name = atom_to_list(Function), |
| 318 | type = ?tMessageType_CALL, |
| 319 | seqid = SeqId}, |
| 320 | ok = thrift_protocol:write(Proto, Begin), |
| 321 | ok = thrift_protocol:write(Proto, {Params, list_to_tuple([Function | Args])}), |
| 322 | ok = thrift_protocol:write(Proto, message_end), |
| 323 | thrift_protocol:flush_transport(Proto), |
| 324 | ok. |
| 325 | |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 326 | receive_function_result(State = #state{protocol = Proto, |
| 327 | service = Service}, |
| 328 | Function) -> |
| 329 | ResultType = Service:function_info(Function, reply_type), |
| 330 | read_result(State, Function, ResultType). |
| 331 | |
| 332 | read_result(_State, |
| 333 | _Function, |
David Reiss | fe931d1 | 2009-03-24 20:02:08 +0000 | [diff] [blame] | 334 | oneway_void) -> |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 335 | {ok, ok}; |
| 336 | |
| 337 | read_result(State = #state{protocol = Proto, |
| 338 | seqid = SeqId}, |
| 339 | Function, |
| 340 | ReplyType) -> |
| 341 | case thrift_protocol:read(Proto, message_begin) of |
| 342 | #protocol_message_begin{seqid = RetSeqId} when RetSeqId =/= SeqId -> |
| 343 | {error, {bad_seq_id, SeqId}}; |
David Reiss | 6b3e40f | 2008-06-11 00:59:03 +0000 | [diff] [blame] | 344 | |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 345 | #protocol_message_begin{type = ?tMessageType_EXCEPTION} -> |
| 346 | handle_application_exception(State); |
David Reiss | 6b3e40f | 2008-06-11 00:59:03 +0000 | [diff] [blame] | 347 | |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 348 | #protocol_message_begin{type = ?tMessageType_REPLY} -> |
| 349 | handle_reply(State, Function, ReplyType) |
| 350 | end. |
| 351 | |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 352 | handle_reply(State = #state{protocol = Proto, |
| 353 | service = Service}, |
| 354 | Function, |
| 355 | ReplyType) -> |
| 356 | {struct, ExceptionFields} = Service:function_info(Function, exceptions), |
| 357 | ReplyStructDef = {struct, [{0, ReplyType}] ++ ExceptionFields}, |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 358 | {ok, Reply} = thrift_protocol:read(Proto, ReplyStructDef), |
| 359 | ReplyList = tuple_to_list(Reply), |
| 360 | true = length(ReplyList) == length(ExceptionFields) + 1, |
| 361 | ExceptionVals = tl(ReplyList), |
| 362 | Thrown = [X || X <- ExceptionVals, |
| 363 | X =/= undefined], |
David Reiss | 2c53403 | 2008-06-11 00:58:00 +0000 | [diff] [blame] | 364 | Result = |
| 365 | case Thrown of |
| 366 | [] when ReplyType == {struct, []} -> |
| 367 | {ok, ok}; |
| 368 | [] -> |
| 369 | {ok, hd(ReplyList)}; |
| 370 | [Exception] -> |
| 371 | {exception, Exception} |
| 372 | end, |
| 373 | ok = thrift_protocol:read(Proto, message_end), |
| 374 | Result. |
David Reiss | 6b3e40f | 2008-06-11 00:59:03 +0000 | [diff] [blame] | 375 | |
David Reiss | 55ff70f | 2008-06-11 00:58:25 +0000 | [diff] [blame] | 376 | handle_application_exception(State = #state{protocol = Proto}) -> |
| 377 | {ok, Exception} = thrift_protocol:read(Proto, |
| 378 | ?TApplicationException_Structure), |
| 379 | ok = thrift_protocol:read(Proto, message_end), |
| 380 | XRecord = list_to_tuple( |
| 381 | ['TApplicationException' | tuple_to_list(Exception)]), |
David Reiss | 1af1868 | 2008-06-11 01:01:36 +0000 | [diff] [blame] | 382 | error_logger:error_msg("X: ~p~n", [XRecord]), |
David Reiss | 55ff70f | 2008-06-11 00:58:25 +0000 | [diff] [blame] | 383 | true = is_record(XRecord, 'TApplicationException'), |
| 384 | {exception, XRecord}. |