2727
2828-include (" amqp_client.hrl" ).
2929
30- -export ([start /2 ]).
30+ -behaviour (gen_server ).
31+
32+ -export ([start_link /2 , register_framing_channel /3 , start_heartbeat /2 ]).
33+ -export ([init /1 , terminate /2 , code_change /3 , handle_call /3 , handle_cast /2 ,
34+ handle_info /2 ]).
3135
3236-record (mr_state , {sock ,
3337 message = none , % % none | {Type, Channel, Length}
3438 framing_channels = amqp_channel_util :new_channel_dict ()}).
3539
36- start (Sock , Framing0Pid ) ->
37- spawn_link (
38- fun () ->
39- State0 = # mr_state {sock = Sock },
40- State1 = register_framing_channel (0 , Framing0Pid , none , State0 ),
41- {ok , _Ref } = rabbit_net :async_recv (Sock , 7 , infinity ),
42- main_loop (State1 )
43- end ).
44-
45- main_loop (State = # mr_state {sock = Sock }) ->
46- receive
47- {inet_async , Sock , _ , _ } = InetAsync ->
48- main_loop (handle_inet_async (InetAsync , State ));
49- {heartbeat , Heartbeat } ->
50- rabbit_heartbeat :start_heartbeat (Sock , Heartbeat ),
51- main_loop (State );
52- {register_framing_channel , Number , Pid , Caller } ->
53- main_loop (register_framing_channel (Number , Pid , Caller , State ));
54- timeout ->
55- ? LOG_WARN (" Main reader (~p ) received timeout from heartbeat, "
56- " exiting~n " , [self ()]),
57- exit (connection_timeout );
58- socket_closing_timeout ->
59- ? LOG_WARN (" Main reader (~p ) received socket_closing_timeout, "
60- " exiting~n " , [self ()]),
61- exit (socket_closing_timeout );
62- close ->
63- close (State );
64- {'DOWN' , _MonitorRef , process , _Pid , _Info } = Down ->
65- main_loop (handle_down (Down , State ));
66- Other ->
67- ? LOG_WARN (" Main reader (~p ) closing: unexpected message ~p " ,
68- [self (), Other ]),
69- exit ({unexpected_message , Other })
70- end .
40+ % %---------------------------------------------------------------------------
41+ % % Interface
42+ % %---------------------------------------------------------------------------
43+
44+ start_link (Sock , Framing0Pid ) ->
45+ gen_server :start_link (? MODULE , [Sock , Framing0Pid ], []).
46+
47+ register_framing_channel (MainReaderPid , Number , FramingPid ) ->
48+ gen_server :call (MainReaderPid ,
49+ {register_framing_channel , Number , FramingPid }, infinity ).
50+
51+ start_heartbeat (MainReaderPid , Heartbeat ) ->
52+ gen_server :cast (MainReaderPid , {heartbeat , Heartbeat }).
53+
54+ % %---------------------------------------------------------------------------
55+ % % gen_server callbacks
56+ % %---------------------------------------------------------------------------
57+
58+ init ([Sock , Framing0Pid ]) ->
59+ State0 = # mr_state {sock = Sock },
60+ State1 = internal_register_framing_channel (0 , Framing0Pid , State0 ),
61+ {ok , _Ref } = rabbit_net :async_recv (Sock , 7 , infinity ),
62+ {ok , State1 }.
63+
64+ terminate (Reason , # mr_state {sock = Sock }) ->
65+ Nice = case Reason of
66+ normal -> true ;
67+ shutdown -> true ;
68+ {shutdown , _ } -> true ;
69+ _ -> false
70+ end ,
71+ ok = case Nice of
72+ true -> rabbit_net :close (Sock );
73+ false -> ok
74+ end .
75+
76+ code_change (_OldVsn , State , _Extra ) ->
77+ State .
78+
79+ handle_call ({register_framing_channel , Number , Pid }, _From , State ) ->
80+ {reply , ok , internal_register_framing_channel (Number , Pid , State )}.
81+
82+ handle_cast ({heartbeat , Heartbeat }, State = # mr_state {sock = Sock }) ->
83+ rabbit_heartbeat :start_heartbeat (Sock , Heartbeat ),
84+ {noreply , State }.
85+
86+ handle_info ({inet_async , _ , _ , _ } = InetAsync , State ) ->
87+ handle_inet_async (InetAsync , State );
88+ handle_info ({'DOWN' , _ , _ , _ , _ } = Down , State ) ->
89+ handle_down (Down , State );
90+ handle_info (timeout , State ) ->
91+ {stop , connection_timeout , State };
92+ handle_info (socket_closing_timeout , State ) ->
93+ {stop , socket_closing_timeout , State };
94+ handle_info (close , State ) ->
95+ {stop , normal , State }.
96+
97+ % %---------------------------------------------------------------------------
98+ % % Internal plumbing
99+ % %---------------------------------------------------------------------------
71100
72101handle_inet_async ({inet_async , Sock , _ , Msg },
73102 State = # mr_state {sock = Sock ,
@@ -79,19 +108,18 @@ handle_inet_async({inet_async, Sock, _, Msg},
79108 case Msg of
80109 {ok , <<Payload :Length /binary , ? FRAME_END >>} ->
81110 case handle_frame (Type , Channel , Payload , State ) of
82- closed_ok -> close ( State ) ;
111+ closed_ok -> { stop , normal , State } ;
83112 _ -> {ok , _Ref } =
84113 rabbit_net :async_recv (Sock , 7 , infinity ),
85- State # mr_state {message = none }
114+ { noreply , State # mr_state {message = none } }
86115 end ;
87116 {ok , <<NewType :8 , NewChannel :16 , NewLength :32 >>} ->
88117 {ok , _Ref } = rabbit_net :async_recv (Sock , NewLength + 1 , infinity ),
89- State # mr_state {message = {NewType , NewChannel , NewLength }};
118+ { noreply , State # mr_state {message = {NewType , NewChannel , NewLength } }};
90119 {error , closed } ->
91- exit ( socket_closed ) ;
120+ { stop , socket_closed , State } ;
92121 {error , Reason } ->
93- ? LOG_WARN (" Socket error: ~p~n " , [Reason ]),
94- exit ({socket_error , Reason })
122+ {stop , {socket_error , Reason }, State }
95123 end .
96124
97125handle_frame (Type , Channel , Payload , State ) ->
@@ -122,29 +150,20 @@ pass_frame(Channel, Frame, #mr_state{framing_channels = Channels}) ->
122150 rabbit_framing_channel :process (FramingPid , Frame )
123151 end .
124152
125- register_framing_channel (Number , Pid , Caller ,
126- State = # mr_state {framing_channels = Channels }) ->
127- NewChannels = amqp_channel_util :register_channel (Number , Pid , Channels ),
128- erlang :monitor (process , Pid ),
129- case Caller of
130- none -> ok ;
131- _ -> Caller ! registered_framing_channel
132- end ,
133- State # mr_state {framing_channels = NewChannels }.
134-
135153handle_down ({'DOWN' , _MonitorRef , process , Pid , Info },
136154 State = # mr_state {framing_channels = Channels }) ->
137155 case amqp_channel_util :is_channel_pid_registered (Pid , Channels ) of
138156 true ->
139157 NewChannels =
140158 amqp_channel_util :unregister_channel_pid (Pid , Channels ),
141- State # mr_state {framing_channels = NewChannels };
159+ { noreply , State # mr_state {framing_channels = NewChannels } };
142160 false ->
143- ? LOG_WARN (" Reader received unexpected DOWN signal from (~p )."
144- " Info: ~p~n " , [Pid , Info ]),
145- exit ({unexpected_down , Pid , Info })
161+ {stop , {unexpected_down , Pid , Info }, State }
146162 end .
147163
148- close (# mr_state {sock = Sock }) ->
149- rabbit_net :close (Sock ),
150- exit (normal ).
164+ internal_register_framing_channel (
165+ Number , Pid , State = # mr_state {framing_channels = Channels }) ->
166+ NewChannels = amqp_channel_util :register_channel (Number , Pid , Channels ),
167+ erlang :monitor (process , Pid ),
168+ State # mr_state {framing_channels = NewChannels }.
169+
0 commit comments