Permalink
Browse files

WHISTLE-571: support BLF subscriptions, also fixed the channel query API

  • Loading branch information...
1 parent 2457ea1 commit 7e1328af1b4a54c0d037a1439078631ec708e7c0 @k-anderson k-anderson committed Feb 14, 2012
@@ -573,7 +573,7 @@ get_fs_app(_Node, _UUID, JObj, <<"presence">>) ->
,{"event_type", "presence"}
,{"alt_event_type", "dialog"}
,{"presence-call-direction", "outbound"}
- ,{"event_cound", "0"}
+ ,{"event_count", "0"}
],
_ = [begin
?LOG("sending presence in event to ~p~n", [Node]),
@@ -23,7 +23,9 @@
%% API
-export([start_link/2]).
-export([swap_call_legs/1]).
--export([create_event/3, publish_event/1]).
+-export([create_event/3]).
+-export([create_event_props/3]).
+-export([publish_event/1]).
-export([transfer/3]).
-export([get_fs_var/4]).
-export([publish_channel_destroy/1]).
@@ -274,35 +276,39 @@ process_channel_event(Props, #state{node=Node}) ->
-spec create_event/3 :: (ne_binary(), 'undefined' | ne_binary(), proplist()) -> proplist().
create_event(EventName, ApplicationName, Props) ->
+ wh_api:default_headers(<<>>, ?EVENT_CAT, EventName, ?APP_NAME, ?APP_VERSION)
+ ++ create_event_props(EventName, ApplicationName, Props).
+
+-spec create_event_props/3 :: (ne_binary(), 'undefined' | ne_binary(), proplist()) -> proplist().
+create_event_props(EventName, ApplicationName, Props) ->
CCVs = ecallmgr_util:custom_channel_vars(Props),
{Mega,Sec,Micro} = erlang:now(),
Timestamp = wh_util:to_binary(((Mega * 1000000 + Sec) * 1000000 + Micro)),
-
- Event = [ KV || {_, V}=KV <- [{<<"Msg-ID">>, props:get_value(<<"Event-Date-Timestamp">>, Props, Timestamp)}
- ,{<<"Timestamp">>, props:get_value(<<"Event-Date-Timestamp">>, Props, Timestamp)}
- ,{<<"Call-ID">>, props:get_value(<<"Caller-Unique-ID">>, Props)}
- ,{<<"Call-Direction">>, props:get_value(<<"Call-Direction">>, Props)}
- ,{<<"Channel-Call-State">>, props:get_value(<<"Channel-Call-State">>, Props)}
- ,{<<"Channel-State">>, get_channel_state(Props)}
- ,{<<"Transfer-History">>, get_transfer_history(Props)}
- ,{<<"Hangup-Cause">>, get_hangup_cause(Props)}
- ,{<<"Hangup-Code">>, get_hangup_code(Props)}
- ,{<<"Disposition">>, get_disposition(Props)}
- ,{<<"Other-Leg-Direction">>, props:get_value(<<"Other-Leg-Direction">>, Props)}
- ,{<<"Other-Leg-Caller-ID-Name">>, props:get_value(<<"Other-Leg-Caller-ID-Name">>, Props)}
- ,{<<"Other-Leg-Caller-ID-Number">>, props:get_value(<<"Other-Leg-Caller-ID-Number">>, Props)}
- ,{<<"Other-Leg-Destination-Number">>, props:get_value(<<"Other-Leg-Destination-Number">>, Props)}
- ,{<<"Other-Leg-Unique-ID">>, props:get_value(<<"Other-Leg-Unique-ID">>, Props,
- props:get_value(<<"variable_holding_uuid">>, Props))}
- ,{<<"Custom-Channel-Vars">>, wh_json:from_list(CCVs)}
- %% this sucks, its leaky but I dont see a better way around it since we need the raw application
- %% name in call_control... (see note in call_control on start_link for why we need to use AMQP
- %% to communicate to it)
- ,{<<"Raw-Application-Name">>, props:get_value(<<"Application">>, Props, ApplicationName)}
- | event_specific(EventName, ApplicationName, Props)
- ],
- V =/= undefined],
- wh_api:default_headers(<<>>, ?EVENT_CAT, EventName, ?APP_NAME, ?APP_VERSION) ++ Event.
+ [ KV || {_, V}=KV <- [{<<"Msg-ID">>, props:get_value(<<"Event-Date-Timestamp">>, Props, Timestamp)}
+ ,{<<"Timestamp">>, props:get_value(<<"Event-Date-Timestamp">>, Props, Timestamp)}
+ ,{<<"Call-ID">>, props:get_value(<<"Caller-Unique-ID">>, Props)}
+ ,{<<"Call-Direction">>, props:get_value(<<"Call-Direction">>, Props)}
+ ,{<<"Channel-Call-State">>, props:get_value(<<"Channel-Call-State">>, Props)}
+ ,{<<"Channel-State">>, get_channel_state(Props)}
+ ,{<<"Transfer-History">>, get_transfer_history(Props)}
+ ,{<<"Hangup-Cause">>, get_hangup_cause(Props)}
+ ,{<<"Hangup-Code">>, get_hangup_code(Props)}
+ ,{<<"Disposition">>, get_disposition(Props)}
+ ,{<<"Other-Leg-Direction">>, props:get_value(<<"Other-Leg-Direction">>, Props)}
+ ,{<<"Other-Leg-Caller-ID-Name">>, props:get_value(<<"Other-Leg-Caller-ID-Name">>, Props)}
+ ,{<<"Other-Leg-Caller-ID-Number">>, props:get_value(<<"Other-Leg-Caller-ID-Number">>, Props)}
+ ,{<<"Other-Leg-Destination-Number">>, props:get_value(<<"Other-Leg-Destination-Number">>, Props)}
+ ,{<<"Other-Leg-Unique-ID">>, props:get_value(<<"Other-Leg-Unique-ID">>, Props,
+ props:get_value(<<"variable_holding_uuid">>, Props))}
+ ,{<<"Custom-Channel-Vars">>, wh_json:from_list(CCVs)}
+ %% this sucks, its leaky but I dont see a better way around it since we need the raw application
+ %% name in call_control... (see note in call_control on start_link for why we need to use AMQP
+ %% to communicate to it)
+ ,{<<"Presence-ID">>, props:get_value(<<"variable_presence_id">>, Props)}
+ ,{<<"Raw-Application-Name">>, props:get_value(<<"Application">>, Props, ApplicationName)}
+ | event_specific(EventName, ApplicationName, Props)
+ ], V =/= undefined
+ ].
-spec publish_event/1 :: (proplist()) -> 'ok'.
publish_event(Props) ->
@@ -38,14 +38,8 @@
-define(FS_TIMEOUT, 5000).
-%% keep in sync with wh_api.hrl OPTIONAL_CHANNEL_QUERY_REQ_HEADERS
--define(CALL_STATUS_HEADERS, [<<"Unique-ID">>, <<"Call-Direction">>, <<"Caller-Caller-ID-Name">>, <<"Caller-Caller-ID-Number">>
- ,<<"Caller-Network-Addr">>, <<"Caller-Destination-Number">>, <<"FreeSWITCH-Hostname">>
- ]).
--define(CALL_STATUS_MAPPING, lists:zip(?CALL_STATUS_HEADERS, [<<"Call-ID">> | wapi_channel_query:optional_headers()])).
-
-spec resource_consume/3 :: (pid(), ne_binary(), wh_json:json_object()) -> {'resource_consumed', binary(), binary(), integer()} |
- {'resource_error', binary() | 'error'}.
+ {'resource_error', binary() | 'error'}.
resource_consume(FsNodePid, Route, JObj) ->
FsNodePid ! {resource_consume, self(), Route, JObj},
receive Resp -> Resp
@@ -595,8 +589,8 @@ get_active_channels(Node) ->
end.
-spec convert_rows/2 :: (atom(), binary()) -> [proplist(),...] | [].
-convert_rows(_, <<"\n0 total.\n">>) ->
- ?LOG("No channels up"),
+convert_rows(Node, <<"\n0 total.\n">>) ->
+ ?LOG("no channels up on node ~s", [Node]),
[];
convert_rows(Node, RowsBin) ->
[_|Rows] = binary:split(RowsBin, <<"\n">>, [global]),
@@ -606,19 +600,24 @@ convert_rows(Node, RowsBin) ->
return_rows(Node, [<<>>|Rs], Acc) ->
return_rows(Node, Rs, Acc);
return_rows(Node, [R|Rs], Acc) ->
- ?LOG("R: ~s", [R]),
case binary:split(R, <<",">>) of
[_Total] ->
- ?LOG("Total: ~s", [_Total]),
+ ?LOG("found ~s calls on node ~s", [_Total, Node]),
return_rows(Node, Rs, Acc);
[UUID|_] ->
- ?LOG("UUID: ~s", [UUID]),
- {ok, Dump} = freeswitch:api(Node, uuid_dump, wh_util:to_list(UUID)),
- DumpProp = ecallmgr_util:eventstr_to_proplist(Dump),
-
- %% Pull wanted data from the converted DUMP proplist
- Prop = [{AMQPKey, props:get_value(FSKey, DumpProp)} || {FSKey, AMQPKey} <- ?CALL_STATUS_MAPPING],
- return_rows(Node, Rs, [ Prop | Acc ])
+ case freeswitch:api(Node, uuid_dump, wh_util:to_list(UUID)) of
+ {'ok', Result} ->
+ Props = ecallmgr_util:eventstr_to_proplist(Result),
+ ApplicationName = props:get_value(<<"variable_current_application">>, Props),
+ JObj = wh_json:from_list([{<<"Switch-Hostname">>, Node}
+ ,{<<"Answer-State">>, props:get_value(<<"Answer-State">>, Props)}
+ | ecallmgr_call_events:create_event_props(<<>>, ApplicationName, Props)
+ ]),
+ return_rows(Node, Rs, [JObj|Acc]);
+ Error ->
+ ?LOG(UUID, "failed to get result from uuid_dump: ~p", [Error]),
+ return_rows(Node, Rs, Acc)
+ end
end;
return_rows(_Node, [], Acc) -> Acc.
@@ -9,7 +9,11 @@
-behaviour(gen_listener).
%% API
--export([start_link/0, handle_channel_query/2, handle_channel_status/2, handle_call_status/2]).
+-export([start_link/0]).
+-export([handle_channel_query/2]).
+-export([handle_channel_status/2]).
+-export([handle_call_status/2]).
+-export([channel_query/1]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, handle_event/2,
@@ -55,9 +59,7 @@ handle_channel_status(JObj, _Props) ->
true = wapi_call:channel_status_req_v(JObj),
wh_util:put_callid(JObj),
CallID = wh_json:get_value(<<"Call-ID">>, JObj),
-
?LOG_START("channel status request received"),
-
case [ecallmgr_fs_node:hostname(NH) || NH <- ecallmgr_fs_sup:node_handlers(), ecallmgr_fs_node:uuid_exists(NH, CallID)] of
[] ->
?LOG("no node found with channel ~s", [CallID]),
@@ -93,9 +95,7 @@ handle_call_status(JObj, _Props) ->
true = wapi_call:call_status_req_v(JObj),
wh_util:put_callid(JObj),
CallID = wh_json:get_value(<<"Call-ID">>, JObj),
-
?LOG("call status request received"),
-
case [NH || NH <- ecallmgr_fs_sup:node_handlers(), ecallmgr_fs_node:uuid_exists(NH, CallID)] of
[] -> ?LOG("no node found with call having leg ~s", [CallID]);
[NodeHandler] ->
@@ -117,30 +117,35 @@ handle_call_status(JObj, _Props) ->
-spec handle_channel_query/2 :: (wh_json:json_object(), proplist()) -> 'ok'.
handle_channel_query(JObj, _Props) ->
- true = wapi_call_query:req_v(JObj),
+ true = wapi_call:channel_query_req_v(JObj),
wh_util:put_callid(JObj),
+ ?LOG("channel query received"),
+ RespQ = wh_json:get_value(<<"Server-ID">>, JObj),
+ Resp = [{<<"Active-Calls">>, channel_query(JObj)}
+ | wh_api:default_headers(?APP_NAME, ?APP_VERSION)],
+ wapi_call:publish_channel_query_resp(RespQ, Resp).
- ?LOG("Channel query received"),
-
- ListOfChannels = [ecallmgr_fs_node:show_channels(Pid) || Pid <- ecallmgr_fs_sup:node_handlers()],
-
+-spec channel_query/1 :: (wh_json:json_object()) -> wh_json:json_objects().
+channel_query(JObj) ->
SearchParams = lists:foldl(fun(Field, Acc) ->
case wh_json:get_value(Field, JObj) of
undefined -> Acc;
Value -> [{Field, Value} | Acc]
end
- end, [], wapi_call:optional_channel_headers()),
-
- case lists:foldl(fun(NodeChannels, Acc) ->
- filter_for_matching_uuids(SearchParams, NodeChannels, Acc)
- end, [], ListOfChannels) of
- [] ->
- ?LOG("No channels found that meet search parameters"),
- ok;
- Matching ->
- RespQ = wh_json:get_value(<<"Server-ID">>, JObj),
- send_channel_query_resp(RespQ, Matching)
- end.
+ end, [], wapi_call:channel_query_search_fields()),
+ Channels = lists:flatten([ecallmgr_fs_node:show_channels(Pid) || Pid <- ecallmgr_fs_sup:node_handlers()]),
+ SearchParams = lists:foldl(fun(Field, Acc) ->
+ case wh_json:get_value(Field, JObj) of
+ undefined -> Acc;
+ Value -> [{Field, Value} | Acc]
+ end
+ end, [], wapi_call:channel_query_search_fields()),
+ lists:foldl(fun(Channel, Results) ->
+ case lists:any(fun({K, V}) -> wh_json:get_value(K, Channel) =:= V end, SearchParams) of
+ true -> [Channel|Results];
+ false -> Results
+ end
+ end, [], Channels).
%%%===================================================================
%%% gen_server callbacks
@@ -235,43 +240,6 @@ code_change(_OldVsn, State, _Extra) ->
%%%===================================================================
%%% Internal functions
%%%===================================================================
-
--spec filter_for_matching_uuids/3 :: (wh_json:json_object(), [proplist(),...], [wh_json:json_object(),...] | []) -> [wh_json:json_object(),...] | [].
-filter_for_matching_uuids(_, [], UUIDs) -> UUIDs;
-filter_for_matching_uuids(SearchParams, [C|Cs], UUIDs) ->
- UUIDs1 = case lists:any(fun({<<"Call-ID">>,_}) -> false;
- ({Key, FSValue}) ->
- case wh_json:get_value(Key, SearchParams) of
- FSValue -> true;
- _ -> false
- end
- end, C) of
- true ->
- try
- [ make_jobj(C) | UUIDs]
- catch
- throw:_E ->
- ?LOG("Throw making jobj: ~p", [_E]),
- UUIDs;
- error:_E ->
- ?LOG("Error making jobj: ~p", [_E]),
- UUIDs
- end;
- false -> UUIDs
- end,
- filter_for_matching_uuids(SearchParams, Cs, UUIDs1).
-
--spec make_jobj/1 :: (proplist()) -> wh_json:json_object().
-make_jobj(C) ->
- wh_json:from_list([{<<"Call-ID">>, wh_json:get_value(<<"Call-ID">>, C)}
- ,{<<"Switch-Hostname">>, wh_json:get_value(<<"Hostname">>, C)}
- ]).
-
-send_channel_query_resp(RespQ, UUIDs) ->
- Resp = [{<<"Active-Calls">>, UUIDs}
- | wh_api:default_headers(?APP_NAME, ?APP_VERSION)],
- wapi_call:publish_channel_resp(RespQ, Resp).
-
-spec create_call_status_resp/2 :: (proplist(), boolean()) -> proplist().
create_call_status_resp(Props, true) ->
{OLCIName, OLCINum} = case props:get_value(<<"Other-Leg-Direction">>, Props) of
@@ -296,6 +264,7 @@ create_call_status_resp(Props, true) ->
,{<<"Other-Leg-Caller-ID-Name">>, OLCIName}
,{<<"Other-Leg-Caller-ID-Number">>, OLCINum}
,{<<"Other-Leg-Destination-Number">>, props:get_value(<<"Other-Leg-Destination-Number">>, Props)}
+ ,{<<"Presence-ID">>, props:get_value(<<"variable_presence_id">>, Props)}
| wh_api:default_headers(?APP_NAME, ?APP_VERSION)];
create_call_status_resp(Props, false) ->
{OLCIName, OLCINum} = case props:get_value(<<"Call-Direction">>, Props) of
@@ -320,4 +289,5 @@ create_call_status_resp(Props, false) ->
,{<<"Other-Leg-Caller-ID-Name">>, OLCIName}
,{<<"Other-Leg-Caller-ID-Number">>, OLCINum}
,{<<"Other-Leg-Destination-Number">>, props:get_value(<<"Caller-Destination-Number">>, Props)}
+ ,{<<"Presence-ID">>, props:get_value(<<"variable_presence_id">>, Props)}
| wh_api:default_headers(?APP_NAME, ?APP_VERSION)].
Oops, something went wrong.

0 comments on commit 7e1328a

Please sign in to comment.