向rabbitmq发送消息

-module(market_subscriber_statistic).

-behaviour(gen_server).

%% API
-export([start_link/1,
         on_connected/1,
         on_disconnected/1,
         on_subscribe/2,
         on_unsubscribe/2]).

%% gen_server callbacks
-export([init/1, 
         handle_call/3, 
         handle_cast/2, 
         handle_info/2,
         terminate/2, 
         code_change/3]).

-define(SERVER, ?MODULE). 

-include("access.hrl").
-include_lib("amqp_client/include/amqp_client.hrl").

-record(state, {client_count,
                instrument_count,
                name,
                timer,
                channel,
                node_id,
                exchange,
                params,
                routing_key,
                today
               }).

-record(md_statistic, {date, node_id, hour, client_count, instrument_count}).

%%%===================================================================
%%% API
%%%===================================================================

%%--------------------------------------------------------------------
%% @doc
%% Starts the server
%%
%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
%% @end
%%--------------------------------------------------------------------
start_link(Params) ->
    gen_server:start_link({local, ?SERVER}, ?MODULE, [Params], []).

on_connected(_Access) ->
    {_, {Hour, _, _}} = erlang:localtime(),
    gen_server:cast(?SERVER, {connected, Hour}).

on_disconnected(_Access) ->
    {_, {Hour, _, _}} = erlang:localtime(),
    gen_server:cast(?SERVER, {disconnected, Hour}).

on_subscribe(_Access, SubCount) ->
    {_, {Hour, _, _}} = erlang:localtime(),
    gen_server:cast(?SERVER, {subscribe, Hour, SubCount}).

on_unsubscribe(_Access, SubCount) ->
    {_, {Hour, _, _}} = erlang:localtime(),
    gen_server:cast(?SERVER, {unsubscribe, Hour, SubCount}).

%%%===================================================================
%%% gen_server callbacks
%%%===================================================================

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Initializes the server
%%
%% @spec init(Args) -> {ok, State} |
%%                     {ok, State, Timeout} |
%%                     ignore |
%%                     {stop, Reason}
%% @end
%%--------------------------------------------------------------------
init([Params]) ->

    Name         = config_val(name, Params, ?MODULE),  
    Exchange     = config_val(exchange, Params, list_to_binary(atom_to_list(?MODULE))),
    RoutingKey   = config_val(routing_key, Params, undefined),
    {ok, NodeId} = application:get_env(market_dispatcher, auth_id),
    
    AmqpParams = #amqp_params_network {
      username       = config_val(amqp_user, Params, <<"guest">>),
      password       = config_val(amqp_pass, Params, <<"guest">>),
      virtual_host   = config_val(amqp_vhost, Params, <<"/">>),
      host           = config_val(amqp_host, Params, "127.0.0.1"),
      port           = config_val(amqp_port, Params, 5672)
     },
  


    Channel = case amqp_channel(AmqpParams) of
                {ok, Channel0} ->
                    lager:info("Amqp Channel start!"),
                    #'exchange.declare_ok'{} = amqp_channel:call(Channel0, #'exchange.declare'{exchange = Exchange, 
                                                                                             type = <<"topic">> }),
                    Channel0;
                {error, Reason} ->
                    lager:error("Amqp channel start error ~p", [Reason]),
                    undefined
              end,

    {ok, Timer} = set_timer(),
    {ok, #state{ client_count     = 0,
                 instrument_count = 0,
                 timer        = Timer, 
                 name         = Name,
                 channel      = Channel,
                 node_id      = NodeId,
                 exchange     = Exchange,
                 params       = AmqpParams,
                 routing_key  = RoutingKey
               }}.

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling call messages
%%
%% @spec handle_call(Request, From, State) ->
%%                                   {reply, Reply, State} |
%%                                   {reply, Reply, State, Timeout} |
%%                                   {noreply, State} |
%%                                   {noreply, State, Timeout} |
%%                                   {stop, Reason, Reply, State} |
%%                                   {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
handle_call(_Request, _From, State) ->
    lager:warning("Can't handle request: ~p", [_Request]),
    {reply, {error, invalid_req}, State}.

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling cast messages
%%
%% @spec handle_cast(Msg, State) -> {noreply, State} |
%%                                  {noreply, State, Timeout} |
%%                                  {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
handle_cast(_Msg, #state{node_id = undefined} = State) ->
    lager:error("Can't handle Msg because auth_id is undefined"),
    {noreply, State};

handle_cast({connected, Hour}, #state{} = State) ->
    #state{client_count = ClientCount, instrument_count = InstrumentCount, 
          node_id = NodeId, channel = Channel} = State,
    send(State, [NodeId, Hour, ClientCount + 1, InstrumentCount], Channel),
    {noreply, State#state{client_count = ClientCount + 1, instrument_count = InstrumentCount}};

handle_cast({disconnected, Hour}, #state{} = State) ->
    #state{client_count = ClientCount, instrument_count = InstrumentCount, 
          node_id = NodeId, channel = Channel} = State,
    send(State, [NodeId, Hour, ClientCount - 1, InstrumentCount], Channel),
    {noreply, State#state{client_count = ClientCount - 1, instrument_count = InstrumentCount}};

handle_cast({subscribe, Hour, Subscribers}, #state{} = State) ->
    #state{client_count = ClientCount, instrument_count = InstrumentCount, 
          node_id = NodeId, channel = Channel} = State,
    send(State, [NodeId, Hour, ClientCount, InstrumentCount + Subscribers], Channel),
    {noreply, State#state{client_count = ClientCount, instrument_count = InstrumentCount + Subscribers}};

handle_cast({unsubscribe, Hour, Subscribers}, #state{} = State) ->
    #state{client_count = ClientCount, instrument_count = InstrumentCount, 
          node_id = NodeId, channel = Channel} = State,
    send(State, [NodeId, Hour, ClientCount, InstrumentCount - Subscribers], Channel),
    {noreply, State#state{client_count = ClientCount, instrument_count = InstrumentCount - Subscribers}};

handle_cast(_Msg, State) ->
    lager:warning("Can't handle msg: ~p", [_Msg]),
    {noreply, State}.


%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling all non call/cast messages
%%
%% @spec handle_info(Info, State) -> {noreply, State} |
%%                                   {noreply, State, Timeout} |
%%                                   {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
% handle_info(write_to_mnesia, #state{} = State) ->
%     #state{timer = Timer, node_id = NodeId, today = Today,
%             md_statistic = MDStatistic} = State,
%     {ok, cancel} = timer:cancel(Timer),
%     {Date, {Hour, _, _}} = erlang:localtime(),
%     EndTime = (calendar:datetime_to_gregorian_seconds({Date, {Hour + 1, 0, 0}}) - 
%                calendar:datetime_to_gregorian_seconds(erlang:localtime())) * 1000,
%     {ok, Timer2} = timer:send_after(EndTime, write_to_mnesia),
%     MDStatRecord = case orddict:find({NodeId, Hour - 1}, MDStatistic) of
%                       error ->
%                           #md_statistic{date = Today, node_id = NodeId, hour = Hour - 1, client_count = 0, instrument_count = 0};
%                       {ok, {ClientCount, InstrumentCount}} ->
%                           #md_statistic{date = Today, node_id = NodeId, hour = Hour - 1, client_count = ClientCount, 
%                             instrument_count = InstrumentCount}
%                    end,
%     mnesia:dirty_write(md_statistic, MDStatRecord),

%     {noreply, State#state{timer = Timer2, today = date_util:today_to_epoch()}};
handle_info(send_data, State) ->
    #state{client_count = ClientCount, instrument_count = InstrumentCount, 
          node_id = NodeId, channel = Channel} = State,
    set_timer(),
    {_, {Hour, _, _}} = erlang:localtime(),
    send(State, [NodeId, Hour, ClientCount, InstrumentCount], Channel),
    {noreply, State};

handle_info(_Info, State) ->
    lager:warning("Can't handle info: ~p", [_Info]),
    {noreply, State}.

%%--------------------------------------------------------------------
%% @private
%% @doc
%% This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any
%% necessary cleaning up. When it returns, the gen_server terminates
%% with Reason. The return value is ignored.
%%
%% @spec terminate(Reason, State) -> void()
%% @end
%%--------------------------------------------------------------------
terminate(_Reason, _State) ->
    ok.

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Convert process state when code is changed
%%
%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
%% @end
%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

%%%===================================================================
%%% Internal functions
%%%===================================================================
send(#state{ name = Name, exchange = Exchange, routing_key = RK } = _State, Message, Channel) ->
    RoutingKey = case RK of
                     undefined -> routing_key(node(), Name);
                     _ -> RK
                 end,
    Publish = #'basic.publish'{ exchange = Exchange, routing_key = RoutingKey },
    Props = #'P_basic'{ content_type = <<"application/json">>},
    Body = jsx:term_to_json(Message),
    Msg = #amqp_msg{ payload = Body, props = Props },
    case Channel of
       undefined -> 
            undefined;
       _ ->
            amqp_channel:cast(Channel, Publish, Msg)
    end.

set_timer() ->
    {_Date, {_Hour, Min, Sec}} = erlang:localtime(),
    EndTime = (3600 - ((Min * 60) + Sec)) * 1000,
    timer:send_after(EndTime, send_data).
  

routing_key(Node, Name) ->
    RoutingKey =  case Name of
                      []   ->  Node;
                      Name ->  string:join([Node, Name], ".")
                  end,
    list_to_binary(RoutingKey).

amqp_channel(AmqpParams) ->
    case maybe_new_pid({AmqpParams, connection},
                       fun() -> amqp_connection:start(AmqpParams) end) of
        {ok, Client} ->
            maybe_new_pid({AmqpParams, channel},
                          fun() -> amqp_connection:open_channel(Client) end);
        Error ->
            Error
    end.

maybe_new_pid(Group, StartFun) ->
    case pg2:get_closest_pid(Group) of
        {error, {no_such_group, _}} ->
            pg2:create(Group),
            maybe_new_pid(Group, StartFun);
        {error, {no_process, _}} ->
            case StartFun() of
                {ok, Pid} ->
                    pg2:join(Group, Pid),
                    {ok, Pid};
                Error ->
                    Error
            end;
        Pid ->
            {ok, Pid}
    end.


config_val(C, Params, Default) ->
  case lists:keyfind(C, 1, Params) of
    {C, V} -> V;
    _ -> Default
  end.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值