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.
jamesaimonetti authored May 1, 2020

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 1d61f9c commit d034e74
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
@@ -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
27 changes: 27 additions & 0 deletions applications/crossbar/priv/api/swagger.json
Original file line number Diff line number Diff line change
@@ -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"
}
},
Original file line number Diff line number Diff line change
@@ -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"
}
},
20 changes: 20 additions & 0 deletions applications/crossbar/priv/oas3/oas3-schemas.yml
Original file line number Diff line number Diff line change
@@ -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':
14 changes: 7 additions & 7 deletions applications/jonny5/src/j5_authz_req.erl
Original file line number Diff line number Diff line change
@@ -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.

@@ -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)
);
@@ -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()) ->
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
@@ -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
@@ -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
@@ -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, []).
76 changes: 36 additions & 40 deletions applications/milliwatt/src/milliwatt_route_req.erl
Original file line number Diff line number Diff line change
@@ -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
@@ -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);
@@ -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)
@@ -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.