%%%------------------------------------------------------------------- %%% @author cheese %%% @copyright (C) 2016, %%% @doc %%% %%% @end %%% Created : 19. Apr 2016 11:12 %%%------------------------------------------------------------------- -module(rabbit_rpc2_reader). -author("cheese"). -behaviour(gen_server). %% API -export([start_link/1, get_queue_name/1]). %% Internal -export([get_process_name/1, get_logfile_name/1, generate_new_resp_queue_name/1]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -define(SERVER, ?MODULE). -include("include/types_rabbit.hrl"). -include("_build/default/lib/amqp_client/include/amqp_client.hrl"). -record(state, { connection_config :: #rabbit_connection_config{}, queue, exchange, arguments, log_file, channel, connection, last_message_date }). %%%=================================================================== %%% API %%%=================================================================== start_link(RabbitConnectionConfig) -> rabbit_rpc2_stat:fold_response_queue(), gen_server:start_link({local, get_process_name(RabbitConnectionConfig)}, ?MODULE, [RabbitConnectionConfig], []). get_queue_name(RabbitConnectionConfig) -> ProcessName = get_process_name(RabbitConnectionConfig), gen_server:call(ProcessName, get_queue_name). %%%=================================================================== %%% gen_server callbacks %%%=================================================================== init([RabbitConnectionConfig]) -> erlang:send_after(2000, self(), check_connection), LogFile = get_logfile_name(RabbitConnectionConfig), logger_Cheese:register_file(LogFile), {ok, #state{ arguments = RabbitConnectionConfig#rabbit_connection_config.arguments, connection_config = RabbitConnectionConfig, exchange = RabbitConnectionConfig#rabbit_connection_config.exchange_response, queue = generate_new_resp_queue_name(RabbitConnectionConfig#rabbit_connection_config.queue_response), log_file = LogFile } }. handle_call(get_queue_name, _From, State) -> {reply, State#state.queue, State}; handle_call(reconnect,_From, #state{connection_config = RabbitConfig, queue = Queue, log_file = LogFile, exchange = Exchange, arguments = Arguments} = State) -> case connectAndDeclare(RabbitConfig, Exchange, Queue,Arguments, LogFile) of {ok, NewChannel, NewConnection} -> {noreply, State#state{channel = NewChannel, connection = NewConnection, last_message_date = calendar:local_time()}}; {error, Reason} -> erlang:error(sql_connection_error), logger_Cheese:info("Check rabbit connection error: ~w~n", [Reason], LogFile), {noreply, State} end; handle_call(_Request, _From, State) -> {reply, ok, State}. handle_cast(_Request, State) -> {noreply, State}. handle_info(check_connection, #state{connection_config = RabbitConfig, queue = Queue, log_file = LogFile, channel = Channel, exchange = Exchange, arguments = Arguments, last_message_date = LastMessage} = State) -> % erlang:send_after(10000, self(), check_connection), % check_timeout(LastMessage, Channel, Connection, LogFile), case Channel of undefined -> logger_Cheese:simple_message("connection undefined", []), case connectAndDeclare(RabbitConfig, Exchange, Queue,Arguments, LogFile) of {ok, NewChannel, NewConnection} -> {noreply, State#state{channel = NewChannel, connection = NewConnection, last_message_date = calendar:local_time()}}; {error, Reason} -> {noreply, State} end; _ -> logger_Cheese:info("reader channel ok~n", [], LogFile), {noreply, State} end; handle_info(#'basic.consume_ok'{}, #state{log_file = LogFile} = State) -> logger_Cheese:info("basic.consume_ok~n", [], LogFile), {noreply, State}; handle_info(#'basic.cancel_ok'{}, #state{log_file = LogFile} = State) -> logger_Cheese:info("basic.cancel_ok~n", [], LogFile), exit({error, "basic.cancel_ok"}), {noreply, State}; handle_info({#'basic.deliver'{delivery_tag = Tag}, #amqp_msg{props = #'P_basic'{correlation_id = CorrelationId}, payload = Body}}, #state{log_file = LogFile, channel = Channel, connection_config = RabbitConfig, queue = QueueName} = State) -> logger_Cheese:info("Receive from rabbit ~s: ~s~n", [CorrelationId, bytes_extension:bin_to_hexstr(Body)], LogFile), amqp_channel:cast(Channel, #'basic.ack'{delivery_tag = Tag}), rabbit_rpc2:on_rabbit_response(RabbitConfig, CorrelationId, Body, QueueName), {noreply, State#state{last_message_date = calendar:local_time()}}; handle_info(Info, #state{log_file = LogFile} = State) -> logger_Cheese:info("Unproc info: ~w~n", [Info], LogFile), timer:sleep(1000), {noreply, State}. terminate(_Reason, _State) -> ok. code_change(_OldVsn, State, _Extra) -> {ok, State}. %%%=================================================================== %%% Internal functions %%%=================================================================== get_process_name(RabbitConnectionConfig) -> list_to_atom(atom_to_list(RabbitConnectionConfig#rabbit_connection_config.process_name) ++ "_rpc2_reader_" ++ binary_to_list(RabbitConnectionConfig#rabbit_connection_config.queue_response)). get_logfile_name(RabbitConnectionConfig) -> "log/" ++ atom_to_list(RabbitConnectionConfig#rabbit_connection_config.process_name) ++ "_rpc2_reader_" ++ binary_to_list(RabbitConnectionConfig#rabbit_connection_config.queue_response) ++ ".log". generate_new_resp_queue_name(Name) -> UUID = bytes_extension:generate_uuid(), {{Year, Month, Day}, {Hour, Min, Second}} = calendar:local_time(), Date = list_to_binary(io_lib:fwrite("~w.~w.~w_~w:~w:~w", [Year, Month, Day, Hour, Min, Second])), <>. % check_timeout(LastMessage, Channel, Connection, LogFile) -> % case LastMessage of % {{Year, Month, Day}, {Hour, Min, Second}} -> % NowSeconds = time_utilites:get_seconds(calendar:local_time()), % LastSeconds = time_utilites:get_seconds({{Year, Month, Day}, {Hour, Min, Second}}), % DiffSeconds = NowSeconds - LastSeconds, % case DiffSeconds > 180 of % true -> % logger_Cheese:info("~w seconds without messages, try to close rabbit response queue ~w~n", [DiffSeconds, Channel], LogFile), % amqp_channel:close(Channel), % amqp_connection:close(Connection), % erlang:error(rabbit_rpc_too_long_time_without_messages); % _ -> % ok % end; % _ -> % logger_Cheese:info("LastMessage: ~w~n", [LastMessage], LogFile), % ok % end. connectAndDeclare(RabbitConfig, Exchange, Queue,Arguments, LogFile) -> logger_Cheese:simple_message("connection undefined", []), Process = get_process_name(RabbitConfig), case rabbit_utilites:connect(Process, RabbitConfig, LogFile) of {ok, NewConnection, NewChannel} -> spawn(rabbit_utilites,connectionMonitor,[NewConnection,LogFile, Process]), logger_Cheese:info("connection create ok. Exchange: ~s~n", [Exchange], LogFile), #'exchange.declare_ok'{} = amqp_channel:call(NewChannel, #'exchange.declare'{exchange = Exchange}), logger_Cheese:info("exchange.declare_ok. Queue: ~s~n", [Queue], LogFile), #'queue.declare_ok'{} = amqp_channel:call(NewChannel, #'queue.declare'{queue = Queue, auto_delete = true, arguments = Arguments}), logger_Cheese:info("queue.declare_ok~n", [], LogFile), #'basic.consume_ok'{} = amqp_channel:call(NewChannel, #'basic.consume'{queue = Queue}), logger_Cheese:info("basic.consume_ok~n", [], LogFile), {ok, NewChannel, NewConnection}; {error, Reason} -> spawn(rabbit_utilites,connectionMonitor,[undefined,LogFile, Process]), erlang:error(sql_connection_error), logger_Cheese:info("Check rabbit connection error: ~w~n", [Reason], LogFile), {error, Reason} end.