Skip to content

Commit

Permalink
Refresh Milliwatt a bit (2600hz#6506)
Browse files Browse the repository at this point in the history
* Refresh Milliwatt a bit

Cleanup module usage, update schema and docs for getting started with
Milliwatt.
  • Loading branch information
jamesaimonetti authored May 1, 2020
1 parent 1d61f9c commit d034e74
Show file tree
Hide file tree
Showing 15 changed files with 225 additions and 81 deletions.
2 changes: 2 additions & 0 deletions applications/crossbar/doc/webhooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,8 @@ curl -v -X DELETE \
Webhooks tracks attempts to send the hook payloads to your URIs. You can get a listing of the more recent attempts to help debug what went wrong.
!!! note By default clusters are not configured to store successful webhook attempts.
> GET /v2/accounts/{ACCOUNT_ID}/webhooks/attempts
```shell
Expand Down
27 changes: 27 additions & 0 deletions applications/crossbar/priv/api/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -36440,6 +36440,33 @@
]
},
"description": "milliwatt tone",
"properties": {
"duration": {
"default": 30000,
"description": "milliwatt tone duration",
"type": "integer"
},
"frequencies": {
"default": [
"2600"
],
"description": "milliwatt tone frequencies",
"items": {
"type": "string"
},
"type": "array"
},
"frequency_off": {
"default": 1000,
"description": "milliwatt tone frequency_off",
"type": "integer"
},
"frequency_on": {
"default": 5000,
"description": "milliwatt tone frequency_on",
"type": "integer"
}
},
"type": "object"
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,33 @@
]
},
"description": "milliwatt tone",
"properties": {
"duration": {
"default": 30000,
"description": "milliwatt tone duration",
"type": "integer"
},
"frequencies": {
"default": [
"2600"
],
"description": "milliwatt tone frequencies",
"items": {
"type": "string"
},
"type": "array"
},
"frequency_off": {
"default": 1000,
"description": "milliwatt tone frequency_off",
"type": "integer"
},
"frequency_on": {
"default": 5000,
"description": "milliwatt tone frequency_on",
"type": "integer"
}
},
"type": "object"
}
},
Expand Down
20 changes: 20 additions & 0 deletions applications/crossbar/priv/oas3/oas3-schemas.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11972,6 +11972,26 @@
'number':
- 5555555551
'description': milliwatt tone
'properties':
'duration':
'default': 30000
'description': milliwatt tone duration
'type': integer
'frequencies':
'default':
- 2600
'description': milliwatt tone frequencies
'items':
'type': string
'type': array
'frequency_off':
'default': 1000
'description': milliwatt tone frequency_off
'type': integer
'frequency_on':
'default': 5000
'description': milliwatt tone frequency_on
'type': integer
'type': object
'type': object
'system_config.mobile':
Expand Down
14 changes: 7 additions & 7 deletions applications/jonny5/src/j5_authz_req.erl
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ maybe_account_limited(Request) ->
case j5_request:is_authorized(R, Limits) of
'true' -> maybe_reseller_limited(R);
'false' ->
lager:debug("account ~s is not authorized to create this channel"
,[AccountId]
),
lager:info("account ~s is not authorized to create this channel"
,[AccountId]
),
send_response(R)
end.

Expand All @@ -40,7 +40,7 @@ maybe_reseller_limited(Request) ->
ResellerId = j5_request:reseller_id(Request),
case j5_request:account_id(Request) =:= ResellerId of
'true' ->
lager:debug("channel belongs to reseller, ignoring reseller billing"),
lager:info("channel belongs to reseller, ignoring reseller billing"),
send_response(
j5_request:authorize_reseller(<<"limits_disabled">>, Request)
);
Expand All @@ -53,9 +53,9 @@ check_reseller_limits(Request, ResellerId) ->
Limits = j5_limits:get(ResellerId),
R = maybe_authorize(Request, Limits),
(not j5_request:is_authorized(R, Limits))
andalso lager:debug("reseller ~s is not authorized to create this channel"
,[ResellerId]
),
andalso lager:info("reseller ~s is not authorized to create this channel"
,[ResellerId]
),
send_response(R).

-spec maybe_authorize(j5_request:request(), j5_limits:limits()) ->
Expand Down
50 changes: 50 additions & 0 deletions applications/milliwatt/doc/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,53 @@
# Milliwatt *Echo and tone for monitoring*

Provides rudimentary testing of RTP via an echo test and a tone test.

## Configuration

Start Milliwatt as well: `sup kapps_controller start_app milliwatt`

Each test can be configured to match a list of numbers or caller IDs. The SIP `to` will be matched against the test's `number` array and the call's caller ID number will be matched against the test's `caller_id` array.

## Echo Test

The `echo` test established an audio path with the caller and echos back any audio received.

The `echo` test is configured in the `system_config/milliwatt` document under the `echo` key:

```json
{"_id":"milliwatt"
,"default":{
"echo":{
"number":["5555555552"]
,"caller_id":["12345"]
}
}
}
```

Additionally, the `echo` test can configure how long to let the call last for: `"echo":{"duration":10000}` where `10000` is 10 seconds (configuration value is in milliseconds).

## Tone Test

The `tone` test will play a specified tone to the caller.

The `tone` test is configured in the `system_config/milliwatt` document under the `tone` key:

```json
{"_id":"milliwatt"
,"default":{
"tone":{
"number":["5555555552"]
,"caller_id":["12345"]
}
}
}
```

Additionally the `tone` test has a few more configuration knobs:

| Key | Description | Default |
| `frequencies` | The list of frequencies to play | `["2600"]` |
| `frequency_on` | How long to play the tone(s) for, in ms | `5000` |
| `frequency_off` | How long to play the tone(s) for, in ms | `30000` |
| `duration` | How long, in milliseconds, to continue the call | `30000` |
7 changes: 7 additions & 0 deletions applications/milliwatt/src/milliwatt.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,12 @@
).
-define(TONE, kapps_config:get_json(?CONFIG_CAT, <<"tone">>, ?DEFAULT_TONE)).

-define(DEFAULT_ECHO, kz_json:from_list(
[{<<"caller_id">>,[]}
,{<<"number">>,[<<"5555555552">>]}
])
).
-define(ECHO, kapps_config:get_json(?CONFIG_CAT, <<"echo">>, ?DEFAULT_ECHO)).

-define(MILLIWATT_HRL, 'true').
-endif.
9 changes: 4 additions & 5 deletions applications/milliwatt/src/milliwatt_echo.erl
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,16 @@

-include("milliwatt.hrl").

-define(DURATION, 10000).
-define(DURATION, 10 * ?MILLISECONDS_IN_SECOND).

-spec exec(kapps_call:call()) -> 'ok'.
exec(Call) ->
lager:info("milliwatt execute action echo", []),
lager:info("milliwatt execute action echo"),
kapps_call_command:answer(Call),
kapps_call_command:echo(Call),
timer:sleep(get_duration()),
kapps_call_command:hangup(Call).

-spec get_duration() -> integer().
-spec get_duration() -> non_neg_integer().
get_duration() ->
JObj = kapps_config:get_json(?CONFIG_CAT, <<"echo">>),
kz_json:get_integer_value(<<"duration">>, JObj, ?DURATION).
kapps_config:get_integer(?CONFIG_CAT, [<<"echo">>, <<"duration">>], ?DURATION).
3 changes: 1 addition & 2 deletions applications/milliwatt/src/milliwatt_listener.erl
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@
-define(BINDINGS, [{'route', [{'types', ?RESOURCE_TYPES_HANDLED}]}
,{'self', []}
]).
-define(RESPONDERS, [{'milliwatt_route_req', [{<<"dialplan">>, <<"route_req">>}]}
]).
-define(RESPONDERS, [{'milliwatt_route_req', [{<<"dialplan">>, <<"route_req">>}]}]).
-define(QUEUE_NAME, <<>>).
-define(QUEUE_OPTIONS, []).
-define(CONSUME_OPTIONS, []).
Expand Down
76 changes: 36 additions & 40 deletions applications/milliwatt/src/milliwatt_route_req.erl
Original file line number Diff line number Diff line change
Expand Up @@ -17,41 +17,36 @@

-define(CONFLICT_ACTION, 'tone').

-define(ECHO, kz_json:from_list(
[{<<"caller_id">>,[]}
,{<<"number">>,[<<"5555555552">>]}
])
).

-define(DEFAULT_ROUTE_WIN_TIMEOUT, 3000).
-define(DEFAULT_ROUTE_WIN_TIMEOUT, 3 * ?MILLISECONDS_IN_SECOND).
-define(ROUTE_WIN_TIMEOUT_KEY, <<"route_win_timeout">>).
-define(ROUTE_WIN_TIMEOUT, kapps_config:get_integer(?CONFIG_CAT, ?ROUTE_WIN_TIMEOUT_KEY, ?DEFAULT_ROUTE_WIN_TIMEOUT)).

-spec handle_req(kz_json:object(), kz_term:proplist()) -> 'ok'.
handle_req(JObj, _Props) ->
'true' = kapi_route:req_v(JObj),
CallId = kz_json:get_value(<<"Call-ID">>, JObj),
kz_log:put_callid(CallId),
Call = kapps_call:from_route_req(JObj),
-type action() :: 'tone' | 'echo'.

-spec handle_req(kapi_route:req(), kz_term:proplist()) -> 'ok'.
handle_req(RouteReq, _Props) ->
'true' = kapi_route:req_v(RouteReq),
kz_log:put_callid(RouteReq),
Call = kapps_call:from_route_req(RouteReq),

%% do magic to determine if we should respond...
case tone_or_echo(Call) of
'undefined' ->
lager:debug("milliwatt does not know what to do with this!", []);
Action ->
send_route_response(Action, JObj, Call)
send_route_response(RouteReq, Call, Action)
end.

-spec send_route_response(atom(), kz_json:object(), kapps_call:call()) -> 'ok'.
send_route_response(Action, JObj, Call) ->
-spec send_route_response(kapi_route:req(), kapps_call:call(), action()) -> 'ok'.
send_route_response(RouteReq, Call, Action) ->
lager:info("milliwatt knows how to route the call! sending park response"),
Resp = props:filter_undefined([{?KEY_MSG_ID, kz_api:msg_id(JObj)}
Resp = props:filter_undefined([{?KEY_MSG_ID, kz_api:msg_id(RouteReq)}
,{?KEY_MSG_REPLY_ID, kapps_call:call_id_direct(Call)}
,{<<"Routes">>, []}
,{<<"Method">>, <<"park">>}
| kz_api:default_headers(?APP_NAME, ?APP_VERSION)
]),
ServerId = kz_api:server_id(JObj),
ServerId = kz_api:server_id(RouteReq),
Publisher = fun(P) -> kapi_route:publish_resp(ServerId, P) end,
case kz_amqp_worker:call(Resp
,Publisher
Expand All @@ -61,29 +56,27 @@ send_route_response(Action, JObj, Call) ->
of
{'ok', RouteWin} ->
lager:info("milliwatt has received a route win"),
execute_action(Action, kapps_call:from_route_win(RouteWin, Call));
execute_action(kapps_call:from_route_win(RouteWin, Call), Action);
{'error', _E} ->
lager:info("callflow didn't received a route win, exiting : ~p", [_E])
end.

-spec execute_action(atom(), kapps_call:call()) -> 'ok'.
execute_action('tone', Call) ->
-spec execute_action(kapps_call:call(), action()) -> 'ok'.
execute_action(Call, 'tone') ->
lager:info("milliwatt will execute action tone", []),
milliwatt_tone:exec(Call);
execute_action('echo', Call) ->
execute_action(Call, 'echo') ->
lager:info("milliwatt will execute action echo", []),
milliwatt_echo:exec(Call).


-spec tone_or_echo(kapps_call:call()) -> 'echo' | 'tone' | 'undefined'.
-spec tone_or_echo(kapps_call:call()) -> action() | 'undefined'.
tone_or_echo(Call) ->
CallJObj = kapps_call:to_json(Call),
From = kz_json:get_binary_value(<<"Caller-ID-Number">>, CallJObj, <<>>),
To = kz_json:get_binary_value(<<"To-User">>, CallJObj, <<>>),
case {kapps_config:get_json(?CONFIG_CAT, <<"echo">>, ?ECHO)
,?TONE
}
of
From = kapps_call:caller_id_number(Call),
To = kapps_call:to_user(Call),

lager:debug("checking whether to handle call to ~s from ~s", [To, From]),

case {?ECHO, ?TONE} of
{'undefined', 'undefined'} -> 'undefined';
{Echo, 'undefined'} ->
maybe_echo(Echo, To, From);
Expand All @@ -110,7 +103,7 @@ maybe_tone(Tone, To, From) ->
end.

-spec maybe_echo_maybe_tone(kz_json:object(), kz_json:object(), kz_term:ne_binary(), kz_term:ne_binary()) ->
'undefined' | 'tone' | 'echo'.
action() | 'undefined'.
maybe_echo_maybe_tone(Echo, Tone, To, From) ->
case {rule_exist(Echo, To, From)
,rule_exist(Tone, To, From)
Expand All @@ -125,11 +118,14 @@ maybe_echo_maybe_tone(Echo, Tone, To, From) ->
end.

-spec rule_exist(kz_json:object(), kz_term:ne_binary(), kz_term:ne_binary()) -> boolean().
rule_exist(JObj, To, From) ->
CallerIds = kz_json:get_ne_value(<<"caller_id">>, JObj, []),
Numbers = kz_json:get_ne_value(<<"number">>, JObj, []),

(not
(not lists:member(To, Numbers))
andalso (not lists:member(From, CallerIds))
).
rule_exist(ActionConfig, To, From) ->
matching_number(ActionConfig, To)
orelse matching_caller_id(ActionConfig, From).

-spec matching_number(kz_json:object(), kz_term:ne_binary()) -> boolean().
matching_number(ActionConfig, To) ->
lists:member(To, kz_json:get_list_value(<<"number">>, ActionConfig, [])).

-spec matching_caller_id(kz_json:object(), kz_term:ne_binary()) -> boolean().
matching_caller_id(ActionConfig, From) ->
lists:member(From, kz_json:get_list_value(<<"caller_id">>, ActionConfig, [])).
Loading

0 comments on commit d034e74

Please sign in to comment.