Fixed punctuation
This commit is contained in:
		
							parent
							
								
									e92bf12c9c
								
							
						
					
					
						commit
						446251e4f8
					
				| 
						 | 
					@ -32,15 +32,16 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-behaviour(gen_server).
 | 
					-behaviour(gen_server).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, handle_info/2]).
 | 
					-export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2,
 | 
				
			||||||
 | 
					         handle_info/2]).
 | 
				
			||||||
-export([call/2, call/3, cast/2, cast/3]).
 | 
					-export([call/2, call/3, cast/2, cast/3]).
 | 
				
			||||||
-export([subscribe/3]).
 | 
					-export([subscribe/3]).
 | 
				
			||||||
-export([register_direct_peer/2]).
 | 
					-export([register_direct_peer/2]).
 | 
				
			||||||
-export([register_return_handler/2]).
 | 
					-export([register_return_handler/2]).
 | 
				
			||||||
-export([register_flow_handler/2]).
 | 
					-export([register_flow_handler/2]).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%% This diagram shows the interaction between the different component processes
 | 
					%% This diagram shows the interaction between the different component
 | 
				
			||||||
%% in an AMQP client scenario.
 | 
					%% processes in an AMQP client scenario.
 | 
				
			||||||
%%
 | 
					%%
 | 
				
			||||||
%%                             message* / reply*        +-------+
 | 
					%%                             message* / reply*        +-------+
 | 
				
			||||||
%%                            +----------------------   | queue |
 | 
					%%                            +----------------------   | queue |
 | 
				
			||||||
| 
						 | 
					@ -62,11 +63,12 @@
 | 
				
			||||||
%%       |
 | 
					%%       |
 | 
				
			||||||
%% [consumer tag --> consumer pid]
 | 
					%% [consumer tag --> consumer pid]
 | 
				
			||||||
%%
 | 
					%%
 | 
				
			||||||
%% * These notifications are processed asynchronously via handle_info/2 callbacks
 | 
					%% These notifications are processed asynchronously via
 | 
				
			||||||
 | 
					%% handle_info/2 callbacks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
% AMQP Channel API methods
 | 
					%% AMQP Channel API methods
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%% Generic AMQP RPC mechanism that expects a pseudo synchronous response
 | 
					%% Generic AMQP RPC mechanism that expects a pseudo synchronous response
 | 
				
			||||||
call(Channel, Method) ->
 | 
					call(Channel, Method) ->
 | 
				
			||||||
| 
						 | 
					@ -84,18 +86,18 @@ cast(Channel, Method) ->
 | 
				
			||||||
cast(Channel, Method, Content) ->
 | 
					cast(Channel, Method, Content) ->
 | 
				
			||||||
    gen_server:cast(Channel, {cast, Method, Content}).
 | 
					    gen_server:cast(Channel, {cast, Method, Content}).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
% Consumer registration
 | 
					%% Consumer registration
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%% Registers a consumer pid with the channel
 | 
					%% Registers a consumer pid with the channel
 | 
				
			||||||
subscribe(Channel, BasicConsume = #'basic.consume'{}, Consumer) ->
 | 
					subscribe(Channel, BasicConsume = #'basic.consume'{}, Consumer) ->
 | 
				
			||||||
    gen_server:call(Channel, {BasicConsume, Consumer}).
 | 
					    gen_server:call(Channel, {BasicConsume, Consumer}).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
% Direct peer registration
 | 
					%% Direct peer registration
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%% Registers the direct channel peer with the state of this channel.
 | 
					%% Registers the direct channel peer with the state of this channel.
 | 
				
			||||||
%% This registration occurs after the amqp_channel gen_server instance
 | 
					%% This registration occurs after the amqp_channel gen_server instance
 | 
				
			||||||
| 
						 | 
					@ -116,9 +118,9 @@ register_return_handler(Channel, ReturnHandler) ->
 | 
				
			||||||
register_flow_handler(Channel, FlowHandler) ->
 | 
					register_flow_handler(Channel, FlowHandler) ->
 | 
				
			||||||
    gen_server:cast(Channel, {register_flow_handler, FlowHandler} ).
 | 
					    gen_server:cast(Channel, {register_flow_handler, FlowHandler} ).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
% Internal plumbing
 | 
					%% Internal plumbing
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
rpc_top_half(Method, From, State = #channel_state{writer_pid = Writer,
 | 
					rpc_top_half(Method, From, State = #channel_state{writer_pid = Writer,
 | 
				
			||||||
                                                  rpc_requests = RequestQueue,
 | 
					                                                  rpc_requests = RequestQueue,
 | 
				
			||||||
| 
						 | 
					@ -136,7 +138,8 @@ rpc_top_half(Method, From, State = #channel_state{writer_pid = Writer,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
rpc_bottom_half(#'channel.close'{reply_code = ReplyCode,
 | 
					rpc_bottom_half(#'channel.close'{reply_code = ReplyCode,
 | 
				
			||||||
                                 reply_text = ReplyText}, State) ->
 | 
					                                 reply_text = ReplyText}, State) ->
 | 
				
			||||||
    io:format("Channel received close from peer, code: ~p , message: ~p~n",[ReplyCode,ReplyText]),
 | 
					    io:format("Channel received close from peer, code: ~p , message: ~p~n",
 | 
				
			||||||
 | 
					              [ReplyCode,ReplyText]),
 | 
				
			||||||
    NewState = channel_cleanup(State),
 | 
					    NewState = channel_cleanup(State),
 | 
				
			||||||
    {stop, normal, NewState};
 | 
					    {stop, normal, NewState};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -163,15 +166,18 @@ resolve_consumer(_ConsumerTag, #channel_state{consumers = []}) ->
 | 
				
			||||||
resolve_consumer(ConsumerTag, #channel_state{consumers = Consumers}) ->
 | 
					resolve_consumer(ConsumerTag, #channel_state{consumers = Consumers}) ->
 | 
				
			||||||
    dict:fetch(ConsumerTag, Consumers).
 | 
					    dict:fetch(ConsumerTag, Consumers).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
register_consumer(ConsumerTag, Consumer, State = #channel_state{consumers = Consumers0}) ->
 | 
					register_consumer(ConsumerTag, Consumer,
 | 
				
			||||||
 | 
					                  State = #channel_state{consumers = Consumers0}) ->
 | 
				
			||||||
    Consumers1 = dict:store(ConsumerTag, Consumer, Consumers0),
 | 
					    Consumers1 = dict:store(ConsumerTag, Consumer, Consumers0),
 | 
				
			||||||
    State#channel_state{consumers = Consumers1}.
 | 
					    State#channel_state{consumers = Consumers1}.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
unregister_consumer(ConsumerTag, State = #channel_state{consumers = Consumers0}) ->
 | 
					unregister_consumer(ConsumerTag,
 | 
				
			||||||
 | 
					                    State = #channel_state{consumers = Consumers0}) ->
 | 
				
			||||||
    Consumers1 = dict:erase(ConsumerTag, Consumers0),
 | 
					    Consumers1 = dict:erase(ConsumerTag, Consumers0),
 | 
				
			||||||
    State#channel_state{consumers = Consumers1}.
 | 
					    State#channel_state{consumers = Consumers1}.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
shutdown_writer(State = #channel_state{close_fun = CloseFun, writer_pid = WriterPid}) ->
 | 
					shutdown_writer(State = #channel_state{close_fun = CloseFun,
 | 
				
			||||||
 | 
					                                       writer_pid = WriterPid}) ->
 | 
				
			||||||
    CloseFun(WriterPid),
 | 
					    CloseFun(WriterPid),
 | 
				
			||||||
    State.
 | 
					    State.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -193,7 +199,7 @@ return_handler(State = #channel_state{return_handler_pid = undefined}) ->
 | 
				
			||||||
return_handler(State = #channel_state{return_handler_pid = ReturnHandler}) ->
 | 
					return_handler(State = #channel_state{return_handler_pid = ReturnHandler}) ->
 | 
				
			||||||
    {ReturnHandler, State}.
 | 
					    {ReturnHandler, State}.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
handle_method(BasicConsumeOk = #'basic.consume_ok'{consumer_tag = ConsumerTag},
 | 
					handle_method(ConsumeOk = #'basic.consume_ok'{consumer_tag = ConsumerTag},
 | 
				
			||||||
              State = #channel_state{anon_sub_requests = Anon,
 | 
					              State = #channel_state{anon_sub_requests = Anon,
 | 
				
			||||||
                                     tagged_sub_requests = Tagged}) ->
 | 
					                                     tagged_sub_requests = Tagged}) ->
 | 
				
			||||||
    {_From, Consumer, State0} =
 | 
					    {_From, Consumer, State0} =
 | 
				
			||||||
| 
						 | 
					@ -206,28 +212,31 @@ handle_method(BasicConsumeOk = #'basic.consume_ok'{consumer_tag = ConsumerTag},
 | 
				
			||||||
                    {empty, _} ->
 | 
					                    {empty, _} ->
 | 
				
			||||||
                        exit(anonymous_queue_empty, ConsumerTag);
 | 
					                        exit(anonymous_queue_empty, ConsumerTag);
 | 
				
			||||||
                    {{value, {F, C}}, NewAnon} ->
 | 
					                    {{value, {F, C}}, NewAnon} ->
 | 
				
			||||||
                        {F,C,State#channel_state{anon_sub_requests = NewAnon}}
 | 
					                        {F, C,
 | 
				
			||||||
 | 
					                         State#channel_state{anon_sub_requests = NewAnon}}
 | 
				
			||||||
                end
 | 
					                end
 | 
				
			||||||
        end,
 | 
					        end,
 | 
				
			||||||
    Consumer ! BasicConsumeOk,
 | 
					    Consumer ! ConsumeOk,
 | 
				
			||||||
    State1 = register_consumer(ConsumerTag, Consumer, State0),
 | 
					    State1 = register_consumer(ConsumerTag, Consumer, State0),
 | 
				
			||||||
    rpc_bottom_half(BasicConsumeOk,State1);
 | 
					    rpc_bottom_half(ConsumeOk, State1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
handle_method(BasicCancelOk = #'basic.cancel_ok'{consumer_tag = ConsumerTag}, State) ->
 | 
					handle_method(CancelOk = #'basic.cancel_ok'{consumer_tag = ConsumerTag},
 | 
				
			||||||
 | 
					              State) ->
 | 
				
			||||||
    Consumer = resolve_consumer(ConsumerTag, State),
 | 
					    Consumer = resolve_consumer(ConsumerTag, State),
 | 
				
			||||||
    Consumer ! BasicCancelOk,
 | 
					    Consumer ! CancelOk,
 | 
				
			||||||
    NewState = unregister_consumer(ConsumerTag, State),
 | 
					    NewState = unregister_consumer(ConsumerTag, State),
 | 
				
			||||||
    rpc_bottom_half(BasicCancelOk, NewState);
 | 
					    rpc_bottom_half(CancelOk, NewState);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
handle_method(ChannelCloseOk = #'channel.close_ok'{}, State) ->
 | 
					handle_method(CloseOk = #'channel.close_ok'{}, State) ->
 | 
				
			||||||
    {noreply, NewState} = rpc_bottom_half(ChannelCloseOk, State),
 | 
					    {noreply, NewState} = rpc_bottom_half(CloseOk, State),
 | 
				
			||||||
    {stop, normal, NewState};
 | 
					    {stop, normal, NewState};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%% This handles the flow control flag that the broker initiates.
 | 
					%% This handles the flow control flag that the broker initiates.
 | 
				
			||||||
%% If defined, it informs the flow control handler to suspend submitting
 | 
					%% If defined, it informs the flow control handler to suspend submitting
 | 
				
			||||||
%% any content bearing methods
 | 
					%% any content bearing methods
 | 
				
			||||||
handle_method(Flow = #'channel.flow'{active = Active},
 | 
					handle_method(Flow = #'channel.flow'{active = Active},
 | 
				
			||||||
              State = #channel_state{writer_pid = Writer, do2 = Do2,
 | 
					              State = #channel_state{writer_pid = Writer,
 | 
				
			||||||
 | 
					                                     do2 = Do2,
 | 
				
			||||||
                                     flow_handler_pid = FlowHandler}) ->
 | 
					                                     flow_handler_pid = FlowHandler}) ->
 | 
				
			||||||
    case FlowHandler of
 | 
					    case FlowHandler of
 | 
				
			||||||
        undefined -> ok;
 | 
					        undefined -> ok;
 | 
				
			||||||
| 
						 | 
					@ -239,9 +248,10 @@ handle_method(Flow = #'channel.flow'{active = Active},
 | 
				
			||||||
handle_method(Method, State) ->
 | 
					handle_method(Method, State) ->
 | 
				
			||||||
    rpc_bottom_half(Method, State).
 | 
					    rpc_bottom_half(Method, State).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
handle_method(BasicDeliver = #'basic.deliver'{consumer_tag = ConsumerTag}, Content, State) ->
 | 
					handle_method(Deliver = #'basic.deliver'{consumer_tag = ConsumerTag},
 | 
				
			||||||
 | 
					              Content, State) ->
 | 
				
			||||||
    Consumer = resolve_consumer(ConsumerTag, State),
 | 
					    Consumer = resolve_consumer(ConsumerTag, State),
 | 
				
			||||||
    Consumer ! {BasicDeliver, Content},
 | 
					    Consumer ! {Deliver, Content},
 | 
				
			||||||
    {noreply, State};
 | 
					    {noreply, State};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%% Why is the consumer a handle_method/3 call with the network driver,
 | 
					%% Why is the consumer a handle_method/3 call with the network driver,
 | 
				
			||||||
| 
						 | 
					@ -257,9 +267,9 @@ handle_method(BasicReturn = #'basic.return'{}, Content, State) ->
 | 
				
			||||||
handle_method(Method, Content, State) ->
 | 
					handle_method(Method, Content, State) ->
 | 
				
			||||||
    rpc_bottom_half( {Method, Content} , State).
 | 
					    rpc_bottom_half( {Method, Content} , State).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
% gen_server callbacks
 | 
					%% gen_server callbacks
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
init([InitialState]) ->
 | 
					init([InitialState]) ->
 | 
				
			||||||
    {ok, InitialState}.
 | 
					    {ok, InitialState}.
 | 
				
			||||||
| 
						 | 
					@ -298,7 +308,8 @@ handle_call({Method = #'basic.consume'{consumer_tag = Tag}, Consumer},
 | 
				
			||||||
    rpc_top_half(Method, From, NewState).
 | 
					    rpc_top_half(Method, From, NewState).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%% Standard implementation of the cast/2 command
 | 
					%% Standard implementation of the cast/2 command
 | 
				
			||||||
handle_cast({cast, Method}, State = #channel_state{writer_pid = Writer, do2 = Do2}) ->
 | 
					handle_cast({cast, Method}, State = #channel_state{writer_pid = Writer,
 | 
				
			||||||
 | 
					                                                   do2 = Do2}) ->
 | 
				
			||||||
    Do2(Writer, Method),
 | 
					    Do2(Writer, Method),
 | 
				
			||||||
    {noreply, State};
 | 
					    {noreply, State};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -336,23 +347,29 @@ handle_cast({register_flow_handler, FlowHandler}, State) ->
 | 
				
			||||||
handle_cast({notify_sent, _Peer}, State) ->
 | 
					handle_cast({notify_sent, _Peer}, State) ->
 | 
				
			||||||
    {noreply, State}.
 | 
					    {noreply, State}.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
% Rabbit Writer API methods (gen_server callbacks).
 | 
					%% Rabbit Writer API methods (gen_server callbacks).
 | 
				
			||||||
% These callbacks are invoked when a direct channel sends messages
 | 
					%% These callbacks are invoked when a direct channel sends messages
 | 
				
			||||||
% to this gen_server instance.
 | 
					%% to this gen_server instance.
 | 
				
			||||||
%----------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
handle_info( {send_command, Method}, State) -> handle_method(Method, State);
 | 
					handle_info( {send_command, Method}, State) ->
 | 
				
			||||||
handle_info( {send_command, Method, Content}, State) -> handle_method(Method, Content, State);
 | 
					    handle_method(Method, State);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					handle_info( {send_command, Method, Content}, State) ->
 | 
				
			||||||
% Network Writer methods (gen_server callbacks).
 | 
					    handle_method(Method, Content, State);
 | 
				
			||||||
% These callbacks are invoked when a network channel sends messages
 | 
					 | 
				
			||||||
% to this gen_server instance.
 | 
					 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
handle_info( {method, Method, none}, State) -> handle_method(Method, State);
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
handle_info( {method, Method, Content}, State) -> handle_method(Method, Content, State);
 | 
					%% Network Writer methods (gen_server callbacks).
 | 
				
			||||||
 | 
					%% These callbacks are invoked when a network channel sends messages
 | 
				
			||||||
 | 
					%% to this gen_server instance.
 | 
				
			||||||
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					handle_info( {method, Method, none}, State) ->
 | 
				
			||||||
 | 
					    handle_method(Method, State);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					handle_info( {method, Method, Content}, State) ->
 | 
				
			||||||
 | 
					    handle_method(Method, Content, State);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%% Handles the delivery of a message from a direct channel
 | 
					%% Handles the delivery of a message from a direct channel
 | 
				
			||||||
| 
						 | 
					@ -375,28 +392,24 @@ handle_info({'EXIT', _Pid, Reason},
 | 
				
			||||||
    NewState = channel_cleanup(State),
 | 
					    NewState = channel_cleanup(State),
 | 
				
			||||||
    {stop, normal, NewState};
 | 
					    {stop, normal, NewState};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%% This is for a race condition between a close.close_ok and a subsequent
 | 
				
			||||||
% This is for a race condition between a close.close_ok and a subsequent channel.open
 | 
					%% channel.open
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
handle_info( {channel_close, Peer}, State ) ->
 | 
					handle_info( {channel_close, Peer}, State ) ->
 | 
				
			||||||
    NewState = channel_cleanup(State),
 | 
					    NewState = channel_cleanup(State),
 | 
				
			||||||
    %% TODO Do we still need this??
 | 
					    %% TODO Do we still need this??
 | 
				
			||||||
    Peer ! handshake,
 | 
					    Peer ! handshake,
 | 
				
			||||||
    {noreply, NewState};
 | 
					    {noreply, NewState};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%% This is for a channel exception that can't be otherwise handled
 | 
				
			||||||
% This is for a channel exception that can't be otherwise handled
 | 
					 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
handle_info( {channel_exception, Channel, Reason}, State) ->
 | 
					handle_info( {channel_exception, Channel, Reason}, State) ->
 | 
				
			||||||
    io:format("Channel ~p is shutting down due to: ~p~n",[Channel, Reason]),
 | 
					    io:format("Channel ~p is shutting down due to: ~p~n",[Channel, Reason]),
 | 
				
			||||||
    NewState = channel_cleanup(State),
 | 
					    NewState = channel_cleanup(State),
 | 
				
			||||||
    {stop, shutdown, NewState}.
 | 
					    {stop, shutdown, NewState}.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
% Rest of the gen_server callbacks
 | 
					%% Rest of the gen_server callbacks
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
terminate(normal, _State) ->
 | 
					terminate(normal, _State) ->
 | 
				
			||||||
    ok;
 | 
					    ok;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,14 +30,15 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-behaviour(gen_server).
 | 
					-behaviour(gen_server).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2, handle_info/2]).
 | 
					-export([init/1, terminate/2, code_change/3, handle_call/3, handle_cast/2,
 | 
				
			||||||
 | 
					         handle_info/2]).
 | 
				
			||||||
-export([open_channel/1, open_channel/3]).
 | 
					-export([open_channel/1, open_channel/3]).
 | 
				
			||||||
-export([start/2, start/3, start/4, close/2]).
 | 
					-export([start/2, start/3, start/4, close/2]).
 | 
				
			||||||
-export([start_link/2, start_link/3, start_link/4]).
 | 
					-export([start_link/2, start_link/3, start_link/4]).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
% AMQP Connection API Methods
 | 
					%% AMQP Connection API Methods
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%% Starts a direct connection to the Rabbit AMQP server, assuming that
 | 
					%% Starts a direct connection to the Rabbit AMQP server, assuming that
 | 
				
			||||||
%% the server is running in the same process space.
 | 
					%% the server is running in the same process space.
 | 
				
			||||||
| 
						 | 
					@ -50,8 +51,12 @@ start(User,Password,ProcLink) when is_boolean(ProcLink) ->
 | 
				
			||||||
    Pid;
 | 
					    Pid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%% Starts a networked conection to a remote AMQP server.
 | 
					%% Starts a networked conection to a remote AMQP server.
 | 
				
			||||||
start(User,Password,Host) -> start(User,Password,Host,<<"/">>,false).
 | 
					start(User, Password, Host) ->
 | 
				
			||||||
start(User,Password,Host,VHost) -> start(User,Password,Host,VHost,false).
 | 
					    start(User, Password, Host, <<"/">>, false).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					start(User, Password, Host, VHost) ->
 | 
				
			||||||
 | 
					    start(User, Password, Host, VHost, false).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
start(User, Password, Host, VHost, ProcLink) ->
 | 
					start(User, Password, Host, VHost, ProcLink) ->
 | 
				
			||||||
    InitialState = #connection_state{username = User,
 | 
					    InitialState = #connection_state{username = User,
 | 
				
			||||||
                                     password = Password,
 | 
					                                     password = Password,
 | 
				
			||||||
| 
						 | 
					@ -60,9 +65,14 @@ start(User,Password,Host,VHost,ProcLink) ->
 | 
				
			||||||
    {ok, Pid} = start_internal(InitialState, amqp_network_driver, ProcLink),
 | 
					    {ok, Pid} = start_internal(InitialState, amqp_network_driver, ProcLink),
 | 
				
			||||||
    Pid.
 | 
					    Pid.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
start_link(User,Password) -> start(User,Password,true).
 | 
					start_link(User, Password) ->
 | 
				
			||||||
start_link(User,Password,Host) -> start(User,Password,Host,<<"/">>,true).
 | 
					    start(User, Password, true).
 | 
				
			||||||
start_link(User,Password,Host,VHost) -> start(User,Password,Host,VHost,true).
 | 
					
 | 
				
			||||||
 | 
					start_link(User, Password, Host) ->
 | 
				
			||||||
 | 
					    start(User, Password, Host, <<"/">>, true).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					start_link(User, Password, Host, VHost) ->
 | 
				
			||||||
 | 
					    start(User, Password, Host, VHost, true).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
start_internal(InitialState, Driver, _Link = true) when is_atom(Driver) ->
 | 
					start_internal(InitialState, Driver, _Link = true) when is_atom(Driver) ->
 | 
				
			||||||
    gen_server:start_link(?MODULE, [InitialState, Driver], []);
 | 
					    gen_server:start_link(?MODULE, [InitialState, Driver], []);
 | 
				
			||||||
| 
						 | 
					@ -73,7 +83,8 @@ start_internal(InitialState, Driver, _Link = false) when is_atom(Driver) ->
 | 
				
			||||||
%% Opens a channel without having to specify a channel number.
 | 
					%% Opens a channel without having to specify a channel number.
 | 
				
			||||||
%% This function assumes that an AMQP connection (networked or direct)
 | 
					%% This function assumes that an AMQP connection (networked or direct)
 | 
				
			||||||
%% has already been successfully established.
 | 
					%% has already been successfully established.
 | 
				
			||||||
open_channel(ConnectionPid) -> open_channel(ConnectionPid, none, "").
 | 
					open_channel(ConnectionPid) ->
 | 
				
			||||||
 | 
					    open_channel(ConnectionPid, none, "").
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%% Opens a channel with a specific channel number.
 | 
					%% Opens a channel with a specific channel number.
 | 
				
			||||||
%% This function assumes that an AMQP connection (networked or direct)
 | 
					%% This function assumes that an AMQP connection (networked or direct)
 | 
				
			||||||
| 
						 | 
					@ -86,9 +97,9 @@ open_channel(ConnectionPid, ChannelNumber, OutOfBand) ->
 | 
				
			||||||
%% Closes the AMQP connection
 | 
					%% Closes the AMQP connection
 | 
				
			||||||
close(ConnectionPid, Close) -> gen_server:call(ConnectionPid, Close).
 | 
					close(ConnectionPid, Close) -> gen_server:call(ConnectionPid, Close).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
% Internal plumbing
 | 
					%% Internal plumbing
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%% Starts a new channel process, invokes the correct driver
 | 
					%% Starts a new channel process, invokes the correct driver
 | 
				
			||||||
%% (network or direct) to perform any environment specific channel setup and
 | 
					%% (network or direct) to perform any environment specific channel setup and
 | 
				
			||||||
| 
						 | 
					@ -175,9 +186,9 @@ allocate_channel_number(Channels, _Max) ->
 | 
				
			||||||
close_connection(Close, From, State = #connection_state{driver = Driver}) ->
 | 
					close_connection(Close, From, State = #connection_state{driver = Driver}) ->
 | 
				
			||||||
    Driver:close_connection(Close, From, State).
 | 
					    Driver:close_connection(Close, From, State).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
% gen_server callbacks
 | 
					%% gen_server callbacks
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
init([InitialState, Driver]) when is_atom(Driver) ->
 | 
					init([InitialState, Driver]) when is_atom(Driver) ->
 | 
				
			||||||
    State = Driver:handshake(InitialState),
 | 
					    State = Driver:handshake(InitialState),
 | 
				
			||||||
| 
						 | 
					@ -195,9 +206,9 @@ handle_call(Close = #'connection.close'{}, From, State) ->
 | 
				
			||||||
handle_cast(_Message, State) ->
 | 
					handle_cast(_Message, State) ->
 | 
				
			||||||
    {noreply, State}.
 | 
					    {noreply, State}.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
% Handle forced close from the broker
 | 
					%% Handle forced close from the broker
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
handle_info({method, #'connection.close'{reply_code = Code,
 | 
					handle_info({method, #'connection.close'{reply_code = Code,
 | 
				
			||||||
                                         reply_text = Text}, _Content},
 | 
					                                         reply_text = Text}, _Content},
 | 
				
			||||||
| 
						 | 
					@ -206,16 +217,18 @@ handle_info({method, #'connection.close'{reply_code = Code,
 | 
				
			||||||
    Driver:handle_broker_close(State),
 | 
					    Driver:handle_broker_close(State),
 | 
				
			||||||
    {stop, normal, State};
 | 
					    {stop, normal, State};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
% Trap exits
 | 
					%% Trap exits
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
handle_info( {'EXIT', Pid, {amqp, Reason, Msg, Context}}, State) ->
 | 
					handle_info( {'EXIT', Pid, {amqp, Reason, Msg, Context}}, State) ->
 | 
				
			||||||
    io:format("Channel Peer ~p sent this message: ~p -> ~p~n",[Pid,Msg,Context]),
 | 
					    io:format("Channel Peer ~p sent this message: ~p -> ~p~n",
 | 
				
			||||||
 | 
					              [Pid, Msg, Context]),
 | 
				
			||||||
    {HardError, Code, Text} = rabbit_framing:lookup_amqp_exception(Reason),
 | 
					    {HardError, Code, Text} = rabbit_framing:lookup_amqp_exception(Reason),
 | 
				
			||||||
    case HardError of
 | 
					    case HardError of
 | 
				
			||||||
        false ->
 | 
					        false ->
 | 
				
			||||||
            io:format("Just trapping this exit and proceding to trap an exit from the client channel process~n"),
 | 
					            io:format("Just trapping this exit and proceding to trap an
 | 
				
			||||||
 | 
					                      exit from the client channel process~n"),
 | 
				
			||||||
            {noreply, State};
 | 
					            {noreply, State};
 | 
				
			||||||
        true ->
 | 
					        true ->
 | 
				
			||||||
            io:format("Hard error: (Code = ~p, Text = ~p)~n", [Code, Text]),
 | 
					            io:format("Hard error: (Code = ~p, Text = ~p)~n", [Code, Text]),
 | 
				
			||||||
| 
						 | 
					@ -226,7 +239,7 @@ handle_info( {'EXIT', Pid, {amqp,Reason,Msg,Context}}, State) ->
 | 
				
			||||||
handle_info( {'EXIT', Pid, normal}, State) ->
 | 
					handle_info( {'EXIT', Pid, normal}, State) ->
 | 
				
			||||||
    {noreply, unregister_channel(Pid, State) };
 | 
					    {noreply, unregister_channel(Pid, State) };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
% This is a special case for abruptly closed socket connections
 | 
					%% This is a special case for abruptly closed socket connections
 | 
				
			||||||
handle_info( {'EXIT', _Pid, {socket_error, Reason}}, State) ->
 | 
					handle_info( {'EXIT', _Pid, {socket_error, Reason}}, State) ->
 | 
				
			||||||
    {stop, {socket_error, Reason}, State};
 | 
					    {stop, {socket_error, Reason}, State};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -234,9 +247,9 @@ handle_info( {'EXIT', Pid, Reason}, State) ->
 | 
				
			||||||
    io:format("Connection: Handling exit from ~p --> ~p~n", [Pid, Reason]),
 | 
					    io:format("Connection: Handling exit from ~p --> ~p~n", [Pid, Reason]),
 | 
				
			||||||
    {noreply, unregister_channel(Pid, State) }.
 | 
					    {noreply, unregister_channel(Pid, State) }.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
% Rest of the gen_server callbacks
 | 
					%% Rest of the gen_server callbacks
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
terminate(_Reason, _State) ->
 | 
					terminate(_Reason, _State) ->
 | 
				
			||||||
    ok.
 | 
					    ok.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,23 +43,31 @@ handshake(ConnectionState = #connection_state{username = User,
 | 
				
			||||||
    UserBin = amqp_util:binary(User),
 | 
					    UserBin = amqp_util:binary(User),
 | 
				
			||||||
    PassBin = amqp_util:binary(Pass),
 | 
					    PassBin = amqp_util:binary(Pass),
 | 
				
			||||||
    rabbit_access_control:user_pass_login(UserBin, PassBin),
 | 
					    rabbit_access_control:user_pass_login(UserBin, PassBin),
 | 
				
			||||||
    rabbit_access_control:check_vhost_access(#user{username = UserBin}, VHostPath),
 | 
					    rabbit_access_control:check_vhost_access(#user{username = UserBin},
 | 
				
			||||||
 | 
					                                             VHostPath),
 | 
				
			||||||
    ConnectionState.
 | 
					    ConnectionState.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
open_channel({_Channel, _OutOfBand}, ChannelPid,
 | 
					open_channel({_Channel, _OutOfBand}, ChannelPid,
 | 
				
			||||||
             State = #connection_state{username = User, vhostpath = VHost}) ->
 | 
					             State = #connection_state{username = User,
 | 
				
			||||||
 | 
					                                       vhostpath = VHost}) ->
 | 
				
			||||||
    UserBin = amqp_util:binary(User),
 | 
					    UserBin = amqp_util:binary(User),
 | 
				
			||||||
    ReaderPid = WriterPid = ChannelPid,
 | 
					    ReaderPid = WriterPid = ChannelPid,
 | 
				
			||||||
    Peer = rabbit_channel:start_link(ReaderPid, WriterPid, UserBin, VHost),
 | 
					    Peer = rabbit_channel:start_link(ReaderPid, WriterPid, UserBin, VHost),
 | 
				
			||||||
    amqp_channel:register_direct_peer(ChannelPid, Peer),
 | 
					    amqp_channel:register_direct_peer(ChannelPid, Peer),
 | 
				
			||||||
    State.
 | 
					    State.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
close_channel(_WriterPid) -> ok.
 | 
					close_channel(_WriterPid) ->
 | 
				
			||||||
 | 
					    ok.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
close_connection(_Close, From, _State) ->
 | 
					close_connection(_Close, From, _State) ->
 | 
				
			||||||
    gen_server:reply(From, #'connection.close_ok'{}).
 | 
					    gen_server:reply(From, #'connection.close_ok'{}).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
do(Writer, Method) -> rabbit_channel:do(Writer, Method).
 | 
					do(Writer, Method) ->
 | 
				
			||||||
do(Writer, Method, Content) -> rabbit_channel:do(Writer, Method, Content).
 | 
					    rabbit_channel:do(Writer, Method).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do(Writer, Method, Content) ->
 | 
				
			||||||
 | 
					    rabbit_channel:do(Writer, Method, Content).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					handle_broker_close(_State) ->
 | 
				
			||||||
 | 
					    ok.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
handle_broker_close(_State) -> ok.
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,21 +40,24 @@
 | 
				
			||||||
% Driver API Methods
 | 
					% Driver API Methods
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
handshake(ConnectionState = #connection_state{serverhost = Host}) ->
 | 
					handshake(State = #connection_state{serverhost = Host}) ->
 | 
				
			||||||
    case gen_tcp:connect(Host, 5672, [binary, {packet, 0},{active,false}]) of
 | 
					    case gen_tcp:connect(Host, 5672,
 | 
				
			||||||
 | 
					                         [binary, {packet, 0}, {active, false}]) of
 | 
				
			||||||
        {ok, Sock} ->
 | 
					        {ok, Sock} ->
 | 
				
			||||||
            ok = gen_tcp:send(Sock, amqp_util:protocol_header()),
 | 
					            ok = gen_tcp:send(Sock, amqp_util:protocol_header()),
 | 
				
			||||||
            Parent = self(),
 | 
					            Parent = self(),
 | 
				
			||||||
            FramingPid = rabbit_framing_channel:start_link(fun(X) -> X end, [Parent]),
 | 
					            FramingPid = rabbit_framing_channel:start_link(fun(X) -> X end,
 | 
				
			||||||
            ReaderPid = spawn_link(?MODULE, start_reader, [Sock, FramingPid]),
 | 
					                                                           [Parent]),
 | 
				
			||||||
 | 
					            ReaderPid = spawn_link(?MODULE, start_reader,
 | 
				
			||||||
 | 
					                                   [Sock, FramingPid]),
 | 
				
			||||||
            WriterPid = start_writer(Sock, 0),
 | 
					            WriterPid = start_writer(Sock, 0),
 | 
				
			||||||
            ConnectionState1 = ConnectionState#connection_state{channel0_writer_pid = WriterPid,
 | 
					            State1 = State#connection_state{channel0_writer_pid = WriterPid,
 | 
				
			||||||
                                            reader_pid = ReaderPid,
 | 
					                                            reader_pid = ReaderPid,
 | 
				
			||||||
                                            sock = Sock},
 | 
					                                            sock = Sock},
 | 
				
			||||||
            ConnectionState2 = network_handshake(WriterPid, ConnectionState1),
 | 
					            State2 = network_handshake(WriterPid, State1),
 | 
				
			||||||
            #connection_state{heartbeat = Heartbeat} = ConnectionState2,
 | 
					            #connection_state{heartbeat = Heartbeat} = State2,
 | 
				
			||||||
            ReaderPid ! {heartbeat, Heartbeat},
 | 
					            ReaderPid ! {heartbeat, Heartbeat},
 | 
				
			||||||
            ConnectionState2;
 | 
					            State2;
 | 
				
			||||||
        {error, Reason} ->
 | 
					        {error, Reason} ->
 | 
				
			||||||
            io:format("Could not start the network driver: ~p~n", [Reason]),
 | 
					            io:format("Could not start the network driver: ~p~n", [Reason]),
 | 
				
			||||||
            exit(Reason)
 | 
					            exit(Reason)
 | 
				
			||||||
| 
						 | 
					@ -89,8 +92,11 @@ close_connection(Close = #'connection.close'{}, From,
 | 
				
			||||||
            exit(timeout_on_exit)
 | 
					            exit(timeout_on_exit)
 | 
				
			||||||
    end.
 | 
					    end.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
do(Writer, Method) -> rabbit_writer:send_command(Writer, Method).
 | 
					do(Writer, Method) ->
 | 
				
			||||||
do(Writer, Method, Content) -> rabbit_writer:send_command(Writer, Method, Content).
 | 
					    rabbit_writer:send_command(Writer, Method).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do(Writer, Method, Content) ->
 | 
				
			||||||
 | 
					    rabbit_writer:send_command(Writer, Method, Content).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
handle_broker_close(#connection_state{channel0_writer_pid = Writer,
 | 
					handle_broker_close(#connection_state{channel0_writer_pid = Writer,
 | 
				
			||||||
                                      reader_pid = Reader}) ->
 | 
					                                      reader_pid = Reader}) ->
 | 
				
			||||||
| 
						 | 
					@ -117,7 +123,8 @@ recv() ->
 | 
				
			||||||
% Internal plumbing
 | 
					% Internal plumbing
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
network_handshake(Writer, State = #connection_state{ vhostpath = VHostPath }) ->
 | 
					network_handshake(Writer,
 | 
				
			||||||
 | 
					                  State = #connection_state{ vhostpath = VHostPath }) ->
 | 
				
			||||||
    #'connection.start'{} = recv(),
 | 
					    #'connection.start'{} = recv(),
 | 
				
			||||||
    do(Writer, start_ok(State)),
 | 
					    do(Writer, start_ok(State)),
 | 
				
			||||||
    #'connection.tune'{channel_max = ChannelMax,
 | 
					    #'connection.tune'{channel_max = ChannelMax,
 | 
				
			||||||
| 
						 | 
					@ -129,7 +136,8 @@ network_handshake(Writer, State = #connection_state{ vhostpath = VHostPath }) ->
 | 
				
			||||||
    do(Writer, TuneOk),
 | 
					    do(Writer, TuneOk),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    %% This is something where I don't understand the protocol,
 | 
					    %% This is something where I don't understand the protocol,
 | 
				
			||||||
    %% What happens if the following command reaches the server before the tune ok?
 | 
					    %% What happens if the following command reaches the server
 | 
				
			||||||
 | 
					    %% before the tune ok?
 | 
				
			||||||
    %% Or doesn't get sent at all?
 | 
					    %% Or doesn't get sent at all?
 | 
				
			||||||
    ConnectionOpen = #'connection.open'{virtual_host = VHostPath,
 | 
					    ConnectionOpen = #'connection.open'{virtual_host = VHostPath,
 | 
				
			||||||
                                        capabilities = <<"">>,
 | 
					                                        capabilities = <<"">>,
 | 
				
			||||||
| 
						 | 
					@ -172,9 +180,9 @@ reader_loop(Sock, Type, Channel, Length) ->
 | 
				
			||||||
                    {ok, _Ref} = prim_inet:async_recv(Sock, 7, -1),
 | 
					                    {ok, _Ref} = prim_inet:async_recv(Sock, 7, -1),
 | 
				
			||||||
                    reader_loop(Sock, undefined, undefined, undefined)
 | 
					                    reader_loop(Sock, undefined, undefined, undefined)
 | 
				
			||||||
            end;
 | 
					            end;
 | 
				
			||||||
        {inet_async, Sock, _, {ok, <<_Type:8,_Channel:16,PayloadSize:32>>}} ->
 | 
					        {inet_async, Sock, _, {ok, <<_Type:8, _Chan:16, PayloadSize:32>>}} ->
 | 
				
			||||||
            {ok, _Ref} = prim_inet:async_recv(Sock, PayloadSize + 1, -1),
 | 
					            {ok, _Ref} = prim_inet:async_recv(Sock, PayloadSize + 1, -1),
 | 
				
			||||||
            reader_loop(Sock, _Type, _Channel, PayloadSize);
 | 
					            reader_loop(Sock, _Type, _Chan, PayloadSize);
 | 
				
			||||||
        {inet_async, Sock, _Ref, {error, closed}} ->
 | 
					        {inet_async, Sock, _Ref, {error, closed}} ->
 | 
				
			||||||
            ok;
 | 
					            ok;
 | 
				
			||||||
        {inet_async, Sock, _Ref, {error, Reason}} ->
 | 
					        {inet_async, Sock, _Ref, {error, Reason}} ->
 | 
				
			||||||
| 
						 | 
					@ -187,9 +195,11 @@ reader_loop(Sock, Type, Channel, Length) ->
 | 
				
			||||||
            start_framing_channel(ChannelPid, ChannelNumber),
 | 
					            start_framing_channel(ChannelPid, ChannelNumber),
 | 
				
			||||||
            reader_loop(Sock, Type, Channel, Length);
 | 
					            reader_loop(Sock, Type, Channel, Length);
 | 
				
			||||||
        timeout ->
 | 
					        timeout ->
 | 
				
			||||||
            io:format("Reader (~p) received timeout from heartbeat, exiting ~n",[self()]);
 | 
					            io:format("Reader (~p) received timeout from heartbeat,
 | 
				
			||||||
 | 
					                       exiting ~n", [self()]);
 | 
				
			||||||
        close ->
 | 
					        close ->
 | 
				
			||||||
            io:format("Reader (~p) received close command, exiting ~n",[self()]);
 | 
					            io:format("Reader (~p) received close command,
 | 
				
			||||||
 | 
					                       exiting ~n", [self()]);
 | 
				
			||||||
        {'EXIT', Pid, _Reason} ->
 | 
					        {'EXIT', Pid, _Reason} ->
 | 
				
			||||||
            [H|_] = get_keys({chpid, Pid}),
 | 
					            [H|_] = get_keys({chpid, Pid}),
 | 
				
			||||||
            erase(H),
 | 
					            erase(H),
 | 
				
			||||||
| 
						 | 
					@ -200,7 +210,8 @@ reader_loop(Sock, Type, Channel, Length) ->
 | 
				
			||||||
    end.
 | 
					    end.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
start_framing_channel(ChannelPid, ChannelNumber) ->
 | 
					start_framing_channel(ChannelPid, ChannelNumber) ->
 | 
				
			||||||
    FramingPid = rabbit_framing_channel:start_link(fun(X) -> link(X), X end, [ChannelPid]),
 | 
					    FramingPid = rabbit_framing_channel:start_link(fun(X) -> link(X), X end,
 | 
				
			||||||
 | 
					                                                   [ChannelPid]),
 | 
				
			||||||
    put({channel, ChannelNumber}, {chpid, FramingPid}).
 | 
					    put({channel, ChannelNumber}, {chpid, FramingPid}).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
handle_frame(Type, Channel, Payload) ->
 | 
					handle_frame(Type, Channel, Payload) ->
 | 
				
			||||||
| 
						 | 
					@ -228,3 +239,4 @@ resolve_receiver(Channel) ->
 | 
				
			||||||
       undefined ->
 | 
					       undefined ->
 | 
				
			||||||
            exit(unknown_channel)
 | 
					            exit(unknown_channel)
 | 
				
			||||||
   end.
 | 
					   end.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,7 +33,9 @@
 | 
				
			||||||
-export([basic_properties/0, protocol_header/0]).
 | 
					-export([basic_properties/0, protocol_header/0]).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
basic_properties() ->
 | 
					basic_properties() ->
 | 
				
			||||||
    #'P_basic'{content_type = <<"application/octet-stream">>, delivery_mode = 1, priority = 0}.
 | 
					    #'P_basic'{content_type = <<"application/octet-stream">>,
 | 
				
			||||||
 | 
					               delivery_mode = 1,
 | 
				
			||||||
 | 
					               priority = 0}.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protocol_header() ->
 | 
					protocol_header() ->
 | 
				
			||||||
    <<"AMQP", 1, 1, ?PROTOCOL_VERSION_MAJOR, ?PROTOCOL_VERSION_MINOR>>.
 | 
					    <<"AMQP", 1, 1, ?PROTOCOL_VERSION_MAJOR, ?PROTOCOL_VERSION_MINOR>>.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,30 +33,39 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-include_lib("eunit/include/eunit.hrl").
 | 
					-include_lib("eunit/include/eunit.hrl").
 | 
				
			||||||
 | 
					
 | 
				
			||||||
basic_get_test() -> test_util:basic_get_test(new_connection()).
 | 
					basic_get_test() -> 
 | 
				
			||||||
 | 
					    test_util:basic_get_test(new_connection()).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
basic_return_test() -> test_util:basic_return_test(new_connection()).
 | 
					basic_return_test() ->
 | 
				
			||||||
 | 
					    test_util:basic_return_test(new_connection()).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
basic_qos_test() -> test_util:basic_qos_test(new_connection()).
 | 
					basic_qos_test() ->
 | 
				
			||||||
 | 
					    test_util:basic_qos_test(new_connection()).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
basic_recover_test() -> test_util:basic_recover_test(new_connection()).
 | 
					basic_recover_test() ->
 | 
				
			||||||
 | 
					    test_util:basic_recover_test(new_connection()).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
basic_consume_test() -> test_util:basic_consume_test(new_connection()).
 | 
					basic_consume_test() ->
 | 
				
			||||||
 | 
					    test_util:basic_consume_test(new_connection()).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
lifecycle_test() -> test_util:lifecycle_test(new_connection()).
 | 
					lifecycle_test() ->
 | 
				
			||||||
 | 
					    test_util:lifecycle_test(new_connection()).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
basic_ack_test() ->test_util:basic_ack_test(new_connection()).
 | 
					basic_ack_test() ->
 | 
				
			||||||
 | 
					    test_util:basic_ack_test(new_connection()).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
command_serialization_test() -> test_util:command_serialization_test(new_connection()).
 | 
					command_serialization_test() ->
 | 
				
			||||||
 | 
					    test_util:command_serialization_test(new_connection()).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%----------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
% This must be kicked off manually because it can only be run after Rabbit
 | 
					%% This must be kicked off manually because it can only be run after Rabbit
 | 
				
			||||||
% has been running for 1 minute
 | 
					%% has been running for 1 minute
 | 
				
			||||||
test_channel_flow() ->
 | 
					test_channel_flow() ->
 | 
				
			||||||
    test_util:channel_flow_test(new_connection()).
 | 
					    test_util:channel_flow_test(new_connection()).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%----------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
% Negative Tests
 | 
					%% Negative Tests
 | 
				
			||||||
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
non_existent_exchange_test() -> 
 | 
					non_existent_exchange_test() -> 
 | 
				
			||||||
    negative_test_util:non_existent_exchange_test(new_connection()).
 | 
					    negative_test_util:non_existent_exchange_test(new_connection()).
 | 
				
			||||||
| 
						 | 
					@ -64,10 +73,12 @@ non_existent_exchange_test() ->
 | 
				
			||||||
queue_unbind_test() ->
 | 
					queue_unbind_test() ->
 | 
				
			||||||
    test_util:queue_unbind_test(new_connection()).
 | 
					    test_util:queue_unbind_test(new_connection()).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%----------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
%% Common Functions
 | 
					%% Common Functions
 | 
				
			||||||
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
new_connection() -> amqp_connection:start("guest", "guest").
 | 
					new_connection() ->
 | 
				
			||||||
 | 
					    amqp_connection:start("guest", "guest").
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_coverage() ->
 | 
					test_coverage() ->
 | 
				
			||||||
    rabbit_misc:enable_cover(),
 | 
					    rabbit_misc:enable_cover(),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,28 @@
 | 
				
			||||||
 | 
					%%   The contents of this file are subject to the Mozilla Public License
 | 
				
			||||||
 | 
					%%   Version 1.1 (the "License"); you may not use this file except in
 | 
				
			||||||
 | 
					%%   compliance with the License. You may obtain a copy of the License at
 | 
				
			||||||
 | 
					%%   http://www.mozilla.org/MPL/
 | 
				
			||||||
 | 
					%%
 | 
				
			||||||
 | 
					%%   Software distributed under the License is distributed on an "AS IS"
 | 
				
			||||||
 | 
					%%   basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 | 
				
			||||||
 | 
					%%   License for the specific language governing rights and limitations
 | 
				
			||||||
 | 
					%%   under the License.
 | 
				
			||||||
 | 
					%%
 | 
				
			||||||
 | 
					%%   The Original Code is the RabbitMQ Erlang Client.
 | 
				
			||||||
 | 
					%%
 | 
				
			||||||
 | 
					%%   The Initial Developers of the Original Code are LShift Ltd.,
 | 
				
			||||||
 | 
					%%   Cohesive Financial Technologies LLC., and Rabbit Technologies Ltd.
 | 
				
			||||||
 | 
					%%
 | 
				
			||||||
 | 
					%%   Portions created by LShift Ltd., Cohesive Financial
 | 
				
			||||||
 | 
					%%   Technologies LLC., and Rabbit Technologies Ltd. are Copyright (C)
 | 
				
			||||||
 | 
					%%   2007 LShift Ltd., Cohesive Financial Technologies LLC., and Rabbit
 | 
				
			||||||
 | 
					%%   Technologies Ltd.;
 | 
				
			||||||
 | 
					%%
 | 
				
			||||||
 | 
					%%   All Rights Reserved.
 | 
				
			||||||
 | 
					%%
 | 
				
			||||||
 | 
					%%   Contributor(s): Ben Hood <0x6e6562@gmail.com>.
 | 
				
			||||||
 | 
					%%
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-module(lib_amqp).
 | 
					-module(lib_amqp).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-include_lib("rabbitmq_server/include/rabbit.hrl").
 | 
					-include_lib("rabbitmq_server/include/rabbit.hrl").
 | 
				
			||||||
| 
						 | 
					@ -21,9 +46,12 @@ declare_exchange(Channel, X) ->
 | 
				
			||||||
declare_exchange(Channel, X, Type) ->
 | 
					declare_exchange(Channel, X, Type) ->
 | 
				
			||||||
    ExchangeDeclare = #'exchange.declare'{exchange = X,
 | 
					    ExchangeDeclare = #'exchange.declare'{exchange = X,
 | 
				
			||||||
                                          type = Type,
 | 
					                                          type = Type,
 | 
				
			||||||
                                          passive = false, durable = false,
 | 
					                                          passive = false,
 | 
				
			||||||
                                          auto_delete = false, internal = false,
 | 
					                                          durable = false,
 | 
				
			||||||
                                          nowait = false, arguments = []},
 | 
					                                          auto_delete = false,
 | 
				
			||||||
 | 
					                                          internal = false,
 | 
				
			||||||
 | 
					                                          nowait = false,
 | 
				
			||||||
 | 
					                                          arguments = []},
 | 
				
			||||||
    amqp_channel:call(Channel, ExchangeDeclare).
 | 
					    amqp_channel:call(Channel, ExchangeDeclare).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
delete_exchange(Channel, X) ->
 | 
					delete_exchange(Channel, X) ->
 | 
				
			||||||
| 
						 | 
					@ -31,9 +59,9 @@ delete_exchange(Channel, X) ->
 | 
				
			||||||
                                        if_unused = false, nowait = false},
 | 
					                                        if_unused = false, nowait = false},
 | 
				
			||||||
    #'exchange.delete_ok'{} = amqp_channel:call(Channel, ExchangeDelete).
 | 
					    #'exchange.delete_ok'{} = amqp_channel:call(Channel, ExchangeDelete).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
% TODO This whole section of optional properties and mandatory flags
 | 
					%% TODO This whole section of optional properties and mandatory flags
 | 
				
			||||||
% may have to be re-thought
 | 
					%% may have to be re-thought
 | 
				
			||||||
publish(Channel, X, RoutingKey, Payload) ->
 | 
					publish(Channel, X, RoutingKey, Payload) ->
 | 
				
			||||||
    publish(Channel, X, RoutingKey, Payload, false).
 | 
					    publish(Channel, X, RoutingKey, Payload, false).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,18 +97,23 @@ publish_internal(Fun, Channel, X, RoutingKey,
 | 
				
			||||||
                       payload_fragments_rev = [Payload]},
 | 
					                       payload_fragments_rev = [Payload]},
 | 
				
			||||||
    Fun(Channel, BasicPublish, Content).
 | 
					    Fun(Channel, BasicPublish, Content).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
close_channel(Channel) ->
 | 
					close_channel(Channel) ->
 | 
				
			||||||
    ChannelClose = #'channel.close'{reply_code = 200, reply_text = <<"Goodbye">>,
 | 
					    ChannelClose = #'channel.close'{reply_code = 200,
 | 
				
			||||||
                                    class_id = 0, method_id = 0},
 | 
					                                    reply_text = <<"Goodbye">>,
 | 
				
			||||||
 | 
					                                    class_id = 0,
 | 
				
			||||||
 | 
					                                    method_id = 0},
 | 
				
			||||||
    #'channel.close_ok'{} = amqp_channel:call(Channel, ChannelClose),
 | 
					    #'channel.close_ok'{} = amqp_channel:call(Channel, ChannelClose),
 | 
				
			||||||
    ok.
 | 
					    ok.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
close_connection(Connection) ->
 | 
					close_connection(Connection) ->
 | 
				
			||||||
    ConnectionClose = #'connection.close'{reply_code = 200, reply_text = <<"Goodbye">>,
 | 
					    ConnectionClose = #'connection.close'{reply_code = 200,
 | 
				
			||||||
                                              class_id = 0, method_id = 0},
 | 
					                                          reply_text = <<"Goodbye">>,
 | 
				
			||||||
    #'connection.close_ok'{} = amqp_connection:close(Connection, ConnectionClose),
 | 
					                                          class_id = 0,
 | 
				
			||||||
 | 
					                                          method_id = 0},
 | 
				
			||||||
 | 
					    #'connection.close_ok'{} = amqp_connection:close(Connection,
 | 
				
			||||||
 | 
					                                                     ConnectionClose),
 | 
				
			||||||
    ok.
 | 
					    ok.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
teardown(Connection, Channel) ->
 | 
					teardown(Connection, Channel) ->
 | 
				
			||||||
| 
						 | 
					@ -174,10 +207,12 @@ delete_queue(Channel, Q) ->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bind_queue(Channel, X, Q, Binding) ->
 | 
					bind_queue(Channel, X, Q, Binding) ->
 | 
				
			||||||
    QueueBind = #'queue.bind'{queue = Q, exchange = X,
 | 
					    QueueBind = #'queue.bind'{queue = Q, exchange = X,
 | 
				
			||||||
                              routing_key = Binding, nowait = false, arguments = []},
 | 
					                              routing_key = Binding,
 | 
				
			||||||
 | 
					                              nowait = false, arguments = []},
 | 
				
			||||||
    #'queue.bind_ok'{} = amqp_channel:call(Channel, QueueBind).
 | 
					    #'queue.bind_ok'{} = amqp_channel:call(Channel, QueueBind).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
unbind_queue(Channel, X, Q, Binding) ->
 | 
					unbind_queue(Channel, X, Q, Binding) ->
 | 
				
			||||||
    Unbind = #'queue.unbind'{queue = Q, exchange = X,
 | 
					    Unbind = #'queue.unbind'{queue = Q, exchange = X,
 | 
				
			||||||
                             routing_key = Binding, arguments = []},
 | 
					                             routing_key = Binding, arguments = []},
 | 
				
			||||||
    #'queue.unbind_ok'{} = amqp_channel:call(Channel, Unbind).
 | 
					    #'queue.unbind_ok'{} = amqp_channel:call(Channel, Unbind).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,7 +35,7 @@ non_existent_exchange_test(Connection) ->
 | 
				
			||||||
    Payload = <<"foobar">>,
 | 
					    Payload = <<"foobar">>,
 | 
				
			||||||
    Channel = lib_amqp:start_channel(Connection),
 | 
					    Channel = lib_amqp:start_channel(Connection),
 | 
				
			||||||
    lib_amqp:declare_exchange(Channel, X),
 | 
					    lib_amqp:declare_exchange(Channel, X),
 | 
				
			||||||
    % Deliberately mix up the routingkey and exchange arguments
 | 
					    %% Deliberately mix up the routingkey and exchange arguments
 | 
				
			||||||
    lib_amqp:publish(Channel, RoutingKey, X, Payload),
 | 
					    lib_amqp:publish(Channel, RoutingKey, X, Payload),
 | 
				
			||||||
    receive
 | 
					    receive
 | 
				
			||||||
        X -> ok
 | 
					        X -> ok
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -65,13 +65,13 @@ teardown_test() ->
 | 
				
			||||||
rpc_test() ->
 | 
					rpc_test() ->
 | 
				
			||||||
    test_util:rpc_test(new_connection()).
 | 
					    test_util:rpc_test(new_connection()).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%----------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
% Negative Tests
 | 
					%% Negative Tests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
non_existent_exchange_test() -> 
 | 
					non_existent_exchange_test() -> 
 | 
				
			||||||
  negative_test_util:non_existent_exchange_test(new_connection()).
 | 
					  negative_test_util:non_existent_exchange_test(new_connection()).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%----------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
%% Common Functions
 | 
					%% Common Functions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
new_connection() ->
 | 
					new_connection() ->
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,34 +35,37 @@
 | 
				
			||||||
-record(publish, {q, x, routing_key, bind_key, payload,
 | 
					-record(publish, {q, x, routing_key, bind_key, payload,
 | 
				
			||||||
                 mandatory = false, immediate = false}).
 | 
					                 mandatory = false, immediate = false}).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
% The latch constant defines how many processes are spawned in order
 | 
					%% The latch constant defines how many processes are spawned in order
 | 
				
			||||||
% to run certain functionality in parallel. It follows the standard
 | 
					%% to run certain functionality in parallel. It follows the standard
 | 
				
			||||||
% countdown latch pattern.
 | 
					%% countdown latch pattern.
 | 
				
			||||||
-define(Latch, 100).
 | 
					-define(Latch, 100).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
% The wait constant defines how long a consumer waits before it
 | 
					%% The wait constant defines how long a consumer waits before it
 | 
				
			||||||
% unsubscribes
 | 
					%% unsubscribes
 | 
				
			||||||
-define(Wait, 200).
 | 
					-define(Wait, 200).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%%%%
 | 
					%%%%
 | 
				
			||||||
%
 | 
					%%
 | 
				
			||||||
% This is an example of how the client interaction should work
 | 
					%% This is an example of how the client interaction should work
 | 
				
			||||||
%
 | 
					%%
 | 
				
			||||||
%   Connection = amqp_connection:start(User, Password, Host),
 | 
					%%   Connection = amqp_connection:start(User, Password, Host),
 | 
				
			||||||
%   Channel = amqp_connection:open_channel(Connection),
 | 
					%%   Channel = amqp_connection:open_channel(Connection),
 | 
				
			||||||
%   %%...do something useful
 | 
					%%   %%...do something useful
 | 
				
			||||||
%   ChannelClose = #'channel.close'{ %% set the appropriate fields },
 | 
					%%   ChannelClose = #'channel.close'{ %% set the appropriate fields },
 | 
				
			||||||
%   amqp_channel:call(Channel, ChannelClose),
 | 
					%%   amqp_channel:call(Channel, ChannelClose),
 | 
				
			||||||
%   ConnectionClose = #'connection.close'{ %% set the appropriate fields },
 | 
					%%   ConnectionClose = #'connection.close'{ %% set the appropriate fields },
 | 
				
			||||||
%   amqp_connection:close(Connection, ConnectionClose).
 | 
					%%   amqp_connection:close(Connection, ConnectionClose).
 | 
				
			||||||
%
 | 
					%%
 | 
				
			||||||
 | 
					
 | 
				
			||||||
lifecycle_test(Connection) ->
 | 
					lifecycle_test(Connection) ->
 | 
				
			||||||
    X = <<"x">>,
 | 
					    X = <<"x">>,
 | 
				
			||||||
    Channel = lib_amqp:start_channel(Connection),
 | 
					    Channel = lib_amqp:start_channel(Connection),
 | 
				
			||||||
    lib_amqp:declare_exchange(Channel, X, <<"topic">>),
 | 
					    lib_amqp:declare_exchange(Channel, X, <<"topic">>),
 | 
				
			||||||
    Parent = self(),
 | 
					    Parent = self(),
 | 
				
			||||||
    [spawn(fun() -> queue_exchange_binding(Channel, X, Parent, Tag) end) || Tag <- lists:seq(1,?Latch)],
 | 
					    [spawn(
 | 
				
			||||||
 | 
					           fun() ->
 | 
				
			||||||
 | 
					                queue_exchange_binding(Channel, X, Parent, Tag) end)
 | 
				
			||||||
 | 
					            || Tag <- lists:seq(1, ?Latch)],
 | 
				
			||||||
    latch_loop(?Latch),
 | 
					    latch_loop(?Latch),
 | 
				
			||||||
    lib_amqp:delete_exchange(Channel, X),
 | 
					    lib_amqp:delete_exchange(Channel, X),
 | 
				
			||||||
    lib_amqp:teardown(Connection, Channel),
 | 
					    lib_amqp:teardown(Connection, Channel),
 | 
				
			||||||
| 
						 | 
					@ -89,8 +92,8 @@ channel_lifecycle_test(Connection) ->
 | 
				
			||||||
    lib_amqp:teardown(Connection, Channel2),
 | 
					    lib_amqp:teardown(Connection, Channel2),
 | 
				
			||||||
    ok.
 | 
					    ok.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
% This is designed to exercize the internal queuing mechanism
 | 
					%% This is designed to exercize the internal queuing mechanism
 | 
				
			||||||
% to ensure that commands are properly serialized
 | 
					%% to ensure that commands are properly serialized
 | 
				
			||||||
command_serialization_test(Connection) ->
 | 
					command_serialization_test(Connection) ->
 | 
				
			||||||
    Channel = lib_amqp:start_channel(Connection),
 | 
					    Channel = lib_amqp:start_channel(Connection),
 | 
				
			||||||
    Parent = self(),
 | 
					    Parent = self(),
 | 
				
			||||||
| 
						 | 
					@ -129,8 +132,8 @@ get_and_assert_equals(Channel, Q, Payload) ->
 | 
				
			||||||
basic_get_test(Connection) ->
 | 
					basic_get_test(Connection) ->
 | 
				
			||||||
    Channel = lib_amqp:start_channel(Connection),
 | 
					    Channel = lib_amqp:start_channel(Connection),
 | 
				
			||||||
    {ok, Q} = setup_publish(Channel),
 | 
					    {ok, Q} = setup_publish(Channel),
 | 
				
			||||||
    % TODO: This could be refactored to use get_and_assert_equals,
 | 
					    %% TODO: This could be refactored to use get_and_assert_equals,
 | 
				
			||||||
    % get_and_assert_empty .... would require another bug though :-)
 | 
					    %% get_and_assert_empty .... would require another bug though :-)
 | 
				
			||||||
    Content = lib_amqp:get(Channel, Q),
 | 
					    Content = lib_amqp:get(Channel, Q),
 | 
				
			||||||
    #content{payload_fragments_rev = PayloadFragments} = Content,
 | 
					    #content{payload_fragments_rev = PayloadFragments} = Content,
 | 
				
			||||||
    ?assertMatch([<<"foobar">>], PayloadFragments),
 | 
					    ?assertMatch([<<"foobar">>], PayloadFragments),
 | 
				
			||||||
| 
						 | 
					@ -230,27 +233,28 @@ basic_recover_test(Connection) ->
 | 
				
			||||||
    end,
 | 
					    end,
 | 
				
			||||||
    lib_amqp:teardown(Connection, Channel).
 | 
					    lib_amqp:teardown(Connection, Channel).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
% QOS is not yet implemented in RabbitMQ
 | 
					%% QOS is not yet implemented in RabbitMQ
 | 
				
			||||||
basic_qos_test(Connection) ->
 | 
					basic_qos_test(Connection) ->
 | 
				
			||||||
    lib_amqp:close_connection(Connection).
 | 
					    lib_amqp:close_connection(Connection).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
% Reject is not yet implemented in RabbitMQ
 | 
					%% Reject is not yet implemented in RabbitMQ
 | 
				
			||||||
basic_reject_test(Connection) ->
 | 
					basic_reject_test(Connection) ->
 | 
				
			||||||
    lib_amqp:close_connection(Connection).
 | 
					    lib_amqp:close_connection(Connection).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%----------------------------------------------------------------------------
 | 
					%%----------------------------------------------------------------------------
 | 
				
			||||||
% Unit test for the direct client
 | 
					%% Unit test for the direct client
 | 
				
			||||||
% This just relies on the fact that a fresh Rabbit VM must consume more than
 | 
					%% This just relies on the fact that a fresh Rabbit VM must consume more than
 | 
				
			||||||
% 0.1 pc of the system memory:
 | 
					%% 0.1 pc of the system memory:
 | 
				
			||||||
% 0. Wait 1 minute to let memsup do stuff
 | 
					%% 0. Wait 1 minute to let memsup do stuff
 | 
				
			||||||
% 1. Make sure that the high watermark is set high
 | 
					%% 1. Make sure that the high watermark is set high
 | 
				
			||||||
% 2. Start a process to receive the pause and resume commands from the broker
 | 
					%% 2. Start a process to receive the pause and resume commands from the broker
 | 
				
			||||||
% 3. Register this as flow control notification handler
 | 
					%% 3. Register this as flow control notification handler
 | 
				
			||||||
% 4. Let the system settle for a little bit
 | 
					%% 4. Let the system settle for a little bit
 | 
				
			||||||
% 5. Set the threshold to the lowest possible value
 | 
					%% 5. Set the threshold to the lowest possible value
 | 
				
			||||||
% 6. When the flow handler receives the pause command, it sets the watermark
 | 
					%% 6. When the flow handler receives the pause command, it sets the watermark
 | 
				
			||||||
%    to a high value in order to get the broker to send the resume command
 | 
					%%    to a high value in order to get the broker to send the resume command
 | 
				
			||||||
% 7. Allow 10 secs to receive the pause and resume, otherwise timeout and fail
 | 
					%% 7. Allow 10 secs to receive the pause and resume, otherwise timeout and
 | 
				
			||||||
 | 
					%%    fail
 | 
				
			||||||
channel_flow_test(Connection) ->
 | 
					channel_flow_test(Connection) ->
 | 
				
			||||||
    X = <<"amq.direct">>,
 | 
					    X = <<"amq.direct">>,
 | 
				
			||||||
    K = Payload = <<"x">>,
 | 
					    K = Payload = <<"x">>,
 | 
				
			||||||
| 
						 | 
					@ -280,9 +284,9 @@ channel_flow_test(Connection) ->
 | 
				
			||||||
        exit(did_not_receive_channel_flow)
 | 
					        exit(did_not_receive_channel_flow)
 | 
				
			||||||
    end.
 | 
					    end.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%----------------------------------------------------------------------------
 | 
					%%----------------------------------------------------------------------------
 | 
				
			||||||
% This is a test, albeit not a unit test, to see if the producer
 | 
					%% This is a test, albeit not a unit test, to see if the producer
 | 
				
			||||||
% handles the effect of being throttled.
 | 
					%% handles the effect of being throttled.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
channel_flow_sync(Connection) ->
 | 
					channel_flow_sync(Connection) ->
 | 
				
			||||||
    start_channel_flow(Connection, fun lib_amqp:publish/4).
 | 
					    start_channel_flow(Connection, fun lib_amqp:publish/4).
 | 
				
			||||||
| 
						 | 
					@ -358,9 +362,9 @@ cf_handler_loop(Producer) ->
 | 
				
			||||||
        stop -> ok
 | 
					        stop -> ok
 | 
				
			||||||
    end.
 | 
					    end.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
% This tests whether RPC over AMQP produces the same result as invoking the
 | 
					%% This tests whether RPC over AMQP produces the same result as invoking the
 | 
				
			||||||
% same argument against the same underlying gen_server instance.
 | 
					%% same argument against the same underlying gen_server instance.
 | 
				
			||||||
rpc_test(Connection) ->
 | 
					rpc_test(Connection) ->
 | 
				
			||||||
    Q = uuid(),
 | 
					    Q = uuid(),
 | 
				
			||||||
    Fun = fun(X) -> X + 1 end,
 | 
					    Fun = fun(X) -> X + 1 end,
 | 
				
			||||||
| 
						 | 
					@ -376,7 +380,7 @@ rpc_test(Connection) ->
 | 
				
			||||||
    amqp_rpc_server:stop(Server),
 | 
					    amqp_rpc_server:stop(Server),
 | 
				
			||||||
    ok.
 | 
					    ok.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%---------------------------------------------------------------------------
 | 
					%%---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setup_publish(Channel) ->
 | 
					setup_publish(Channel) ->
 | 
				
			||||||
    Publish = #publish{routing_key = <<"a.b.c.d">>,
 | 
					    Publish = #publish{routing_key = <<"a.b.c.d">>,
 | 
				
			||||||
| 
						 | 
					@ -409,7 +413,9 @@ setup_exchange(Channel, Q, X, Binding) ->
 | 
				
			||||||
    lib_amqp:bind_queue(Channel, X, Q, Binding),
 | 
					    lib_amqp:bind_queue(Channel, X, Q, Binding),
 | 
				
			||||||
    ok.
 | 
					    ok.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
latch_loop(0) -> ok;
 | 
					latch_loop(0) ->
 | 
				
			||||||
 | 
					    ok;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
latch_loop(Latch) ->
 | 
					latch_loop(Latch) ->
 | 
				
			||||||
    receive
 | 
					    receive
 | 
				
			||||||
        finished ->
 | 
					        finished ->
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue