From b5266ed6b44a8219be55a3f81726dbde69e8994a Mon Sep 17 00:00:00 2001 From: Andy Newlands Date: Tue, 8 Nov 2016 13:47:37 +0000 Subject: [PATCH] FS-9325 [mod_dptools] Priority flag for faster bind_digit_action matches Add exec: flag, 'P' (for "Priority") to bind_digit_action so that a match is returned as soon as it is found, without waiting for the inter-digit timeout to expire. This can be very useful where the system needs to be more responsive to the user. By default, if multiple bindings are enabled and one or more use a regex, switch_ivr_dmachine_check_match waits for the inter-digit timeout to expire before returning a match. This ensures overlapping patterns, such as "^\d{4}$" and "^\12{3}$" can both be reliably matched When the 'P' flag is specified with bind_digit_action, whose action is exec, a match is returned as soon as the condition is satisfied, regardless of whether or not a longer match may be possible if further digits were entered. For example: The first example causes a match to be returned immediately after the 2nd digit is received, whereas the second example defaults to waiting for the inter-digit timeout to expire before returning. In cases where the 'P' flag is used with a regex and string, and both are matched, the more explicit, string match will be returned. For example: If "*12" is matched, myotherextn is executed, because "*12" is more explicit/specific than "^*\d{2}$" If the 'P'(riority) flag is not used, behaviour is unchanged from previous versions. This ensures backward compatibility. FS-9325 #resolve --- src/include/switch_ivr.h | 1 + .../mod_conference/conference_member.c | 3 +-- .../applications/mod_dptools/mod_dptools.c | 22 ++++++++++++++++++- src/mod/applications/mod_httapi/mod_httapi.c | 4 ++-- src/switch_ivr_async.c | 21 +++++++++--------- 5 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h index 712179d783..00488380ed 100644 --- a/src/include/switch_ivr.h +++ b/src/include/switch_ivr.h @@ -989,6 +989,7 @@ SWITCH_DECLARE(void) switch_ivr_dmachine_destroy(switch_ivr_dmachine_t **dmachin SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_bind(switch_ivr_dmachine_t *dmachine, const char *realm, const char *digits, + switch_byte_t is_priority, int32_t key, switch_ivr_dmachine_callback_t callback, void *user_data); diff --git a/src/mod/applications/mod_conference/conference_member.c b/src/mod/applications/mod_conference/conference_member.c index 064d12edac..71b50984f2 100644 --- a/src/mod/applications/mod_conference/conference_member.c +++ b/src/mod/applications/mod_conference/conference_member.c @@ -85,8 +85,7 @@ void conference_member_do_binding(conference_member_t *member, conference_key_ca } binding->handler = handler; - switch_ivr_dmachine_bind(member->dmachine, "conf", digits, 0, conference_loop_dmachine_dispatcher, binding); - + switch_ivr_dmachine_bind(member->dmachine, "conf", digits, 0, 0, conference_loop_dmachine_dispatcher, binding); } void conference_member_bind_controls(conference_member_t *member, const char *controls) diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index 28b1de428f..6c952c9944 100644 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -346,6 +346,7 @@ static void bind_to_session(switch_core_session_t *session, switch_ivr_dmachine_t *dmachine; switch_channel_t *channel = switch_core_session_get_channel(session); const char *terminators = NULL; + switch_byte_t is_priority = 0; if (!(dmachine = switch_core_session_get_dmachine(session, target))) { uint32_t digit_timeout = 1500; @@ -372,8 +373,27 @@ static void bind_to_session(switch_core_session_t *session, act->value = switch_core_session_strdup(session, arg3); act->target = bind_target; act->session = session; - switch_ivr_dmachine_bind(dmachine, act->realm, act->input, 0, digit_action_callback, act); + if (!strncasecmp(act->string, "exec", 4) || !strncasecmp(act->string, "api:", 4)) { + char *flags, *e; + char *string = switch_core_session_strdup(session, act->string); + + string += 4; + if (*string == '[') { + flags = string; + if ((e = switch_find_end_paren(flags, '[', ']'))) { + if (e && *(e+1) == ':') { + flags++; + *e = '\0'; + if (strchr(flags, 'P')) + is_priority = 1; + } + } + } + } + + switch_ivr_dmachine_bind(dmachine, act->realm, act->input, is_priority, 0, digit_action_callback, act); + if ((terminators = switch_channel_get_variable(channel, "bda_terminators"))) { switch_ivr_dmachine_set_terminators(dmachine, terminators); } diff --git a/src/mod/applications/mod_httapi/mod_httapi.c b/src/mod/applications/mod_httapi/mod_httapi.c index 74de05e842..50c534c2d4 100644 --- a/src/mod/applications/mod_httapi/mod_httapi.c +++ b/src/mod/applications/mod_httapi/mod_httapi.c @@ -563,7 +563,7 @@ static switch_status_t parse_playback(const char *tag_name, client_t *client, sw action_binding->error_file = (char *) error_file; action_binding->parent = top_action_binding; - switch_ivr_dmachine_bind(dmachine, action_binding->realm, action_binding->input, 0, digit_action_callback, action_binding); + switch_ivr_dmachine_bind(dmachine, action_binding->realm, action_binding->input, 0, 0, digit_action_callback, action_binding); bind = bind->next; } @@ -1067,7 +1067,7 @@ static switch_status_t parse_record(const char *tag_name, client_t *client, swit action_binding->error_file = (char *) error_file; action_binding->parent = top_action_binding; - switch_ivr_dmachine_bind(dmachine, action_binding->realm, action_binding->input, 0, digit_action_callback, action_binding); + switch_ivr_dmachine_bind(dmachine, action_binding->realm, action_binding->input, 0, 0, digit_action_callback, action_binding); bind = bind->next; } diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index 8df35b5a0b..6b8e4d933d 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -44,6 +44,7 @@ struct switch_ivr_dmachine_binding { uint8_t rmatch; switch_ivr_dmachine_callback_t callback; switch_byte_t is_regex; + switch_byte_t is_priority; void *user_data; struct switch_ivr_dmachine_binding *next; }; @@ -247,7 +248,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_clear_realm(switch_ivr_dmach SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_bind(switch_ivr_dmachine_t *dmachine, const char *realm, - const char *digits, + const char *digits, + switch_byte_t is_priority, int32_t key, switch_ivr_dmachine_callback_t callback, void *user_data) @@ -291,6 +293,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_bind(switch_ivr_dmachine_t * binding->key = key; binding->digits = switch_core_strdup(dmachine->pool, digits); + binding->is_priority = is_priority; binding->callback = callback; binding->user_data = user_data; @@ -348,11 +351,7 @@ static dm_match_t switch_ivr_dmachine_check_match(switch_ivr_dmachine_t *dmachin if (bp->is_regex) { switch_status_t r_status = switch_regex_match(dmachine->digits, bp->digits); - if (r_status == SWITCH_STATUS_SUCCESS) { - bp->rmatch++; - } else { - bp->rmatch = 0; - } + bp->rmatch = r_status == SWITCH_STATUS_SUCCESS; rmatches++; pmatches++; @@ -360,7 +359,9 @@ static dm_match_t switch_ivr_dmachine_check_match(switch_ivr_dmachine_t *dmachin } else { if (!strncmp(dmachine->digits, bp->digits, strlen(dmachine->digits))) { pmatches++; - ematches = 1; + if (dmachine->cur_digit_len == strlen(bp->digits)) { + ematches++; + } } } } @@ -382,7 +383,7 @@ static dm_match_t switch_ivr_dmachine_check_match(switch_ivr_dmachine_t *dmachin for(bp = dmachine->realm->binding_list; bp; bp = bp->next) { if (bp->is_regex) { if (bp->rmatch) { - if (is_timeout || (bp == dmachine->realm->binding_list && !bp->next)) { + if ((bp->is_priority && ! ematches) || is_timeout || (bp == dmachine->realm->binding_list && !bp->next)) { best = DM_MATCH_EXACT; exact_bp = bp; break; @@ -392,10 +393,10 @@ static dm_match_t switch_ivr_dmachine_check_match(switch_ivr_dmachine_t *dmachin } else { int pmatch = !strncmp(dmachine->digits, bp->digits, strlen(dmachine->digits)); - if (!exact_bp && pmatch && (((pmatches == 1 || ematches == 1) && !rmatches) || is_timeout) && !strcmp(bp->digits, dmachine->digits)) { + if (!exact_bp && pmatch && (!rmatches || bp->is_priority || is_timeout) && !strcmp(bp->digits, dmachine->digits)) { best = DM_MATCH_EXACT; exact_bp = bp; - if (dmachine->cur_digit_len == dmachine->max_digit_len) break; + if (bp->is_priority || dmachine->cur_digit_len == dmachine->max_digit_len) break; } if (!(both_bp && partial_bp) && strlen(bp->digits) != strlen(dmachine->digits) && pmatch) {