app_queue: Add support for applying caller priority change immediately.

The app_queue module provides both an AMI action and a CLI command
to change the priority of a caller in a queue. Up to now this change
of priority has only been reflected to new callers into the queue.

This change adds an "immediate" option to both the AMI action and
CLI command which immediately applies the priority change respective
to the other callers already in the queue. This can allow, for example,
a caller to be placed at the head of the queue immediately if their
priority is sufficient.

Resolves: #202

UserNote: The 'queue priority caller' CLI command and
'QueueChangePriorityCaller' AMI action now have an 'immediate'
argument which allows the caller priority change to be reflected
immediately, causing the position of a caller to move within the
queue depending on the priorities of the other callers.

(cherry picked from commit 879d4ff56a)
This commit is contained in:
Joshua C. Colp 2023-07-07 11:29:07 -03:00 committed by Asterisk Development Team
parent c0898cb265
commit ef7a9e91fe
1 changed files with 73 additions and 15 deletions

View File

@ -1059,6 +1059,9 @@
<parameter name="Priority" required="true">
<para>Priority value for change for caller on queue.</para>
</parameter>
<parameter name="Immediate">
<para>When set to yes will cause the priority change to be reflected immediately, causing the channel to change position within the queue.</para>
</parameter>
</syntax>
<description>
</description>
@ -2109,8 +2112,10 @@ static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, st
/* every queue_ent must have a reference to it's parent call_queue, this
* reference does not go away until the end of the queue_ent's life, meaning
* that even when the queue_ent leaves the call_queue this ref must remain. */
queue_ref(q);
new->parent = q;
if (!new->parent) {
queue_ref(q);
new->parent = q;
}
new->pos = ++(*pos);
new->opos = *pos;
}
@ -7711,10 +7716,10 @@ static int add_to_queue(const char *queuename, const char *interface, const char
* \retval RES_OKAY change priority
* \retval RES_NOT_CALLER queue exists but no caller
*/
static int change_priority_caller_on_queue(const char *queuename, const char *caller, int priority)
static int change_priority_caller_on_queue(const char *queuename, const char *caller, int priority, int immediate)
{
struct call_queue *q;
struct queue_ent *qe;
struct queue_ent *current, *prev = NULL, *caller_qe = NULL;
int res = RES_NOSUCHQUEUE;
/*! \note Ensure the appropriate realtime queue is loaded. Note that this
@ -7725,14 +7730,57 @@ static int change_priority_caller_on_queue(const char *queuename, const char *ca
ao2_lock(q);
res = RES_NOT_CALLER;
for (qe = q->head; qe; qe = qe->next) {
if (strcmp(ast_channel_name(qe->chan), caller) == 0) {
for (current = q->head; current; current = current->next) {
if (strcmp(ast_channel_name(current->chan), caller) == 0) {
ast_debug(1, "%s Caller new priority %d in queue %s\n",
caller, priority, queuename);
qe->prio = priority;
current->prio = priority;
if (immediate) {
/* This caller is being immediately moved in the queue so remove them */
if (prev) {
prev->next = current->next;
} else {
q->head = current->next;
}
caller_qe = current;
/* The position for all callers is not recalculated in here as it will
* be updated when the moved caller is inserted back into the queue
*/
}
res = RES_OKAY;
break;
} else if (immediate) {
prev = current;
}
}
if (caller_qe) {
int inserted = 0, pos = 0;
/* If a caller queue entry exists, we are applying their priority immediately
* and have to reinsert them at the correct position.
*/
prev = NULL;
current = q->head;
while (current) {
if (!inserted && (caller_qe->prio > current->prio)) {
insert_entry(q, prev, caller_qe, &pos);
inserted = 1;
}
/* We always update the position as it may have changed */
current->pos = ++pos;
/* Move to the next caller in the queue */
prev = current;
current = current->next;
}
if (!inserted) {
insert_entry(q, prev, caller_qe, &pos);
}
}
ao2_unlock(q);
return res;
}
@ -10909,12 +10957,13 @@ static int manager_queue_member_penalty(struct mansession *s, const struct messa
static int manager_change_priority_caller_on_queue(struct mansession *s, const struct message *m)
{
const char *queuename, *caller, *priority_s;
int priority = 0;
const char *queuename, *caller, *priority_s, *immediate_s;
int priority = 0, immediate = 0;
queuename = astman_get_header(m, "Queue");
caller = astman_get_header(m, "Caller");
priority_s = astman_get_header(m, "Priority");
immediate_s = astman_get_header(m, "Immediate");
if (ast_strlen_zero(queuename)) {
astman_send_error(s, m, "'Queue' not specified.");
@ -10934,7 +10983,11 @@ static int manager_change_priority_caller_on_queue(struct mansession *s, const s
return 0;
}
switch (change_priority_caller_on_queue(queuename, caller, priority)) {
if (!ast_strlen_zero(immediate_s)) {
immediate = ast_true(immediate_s);
}
switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
case RES_OKAY:
astman_send_ack(s, m, "Priority change for caller on queue");
break;
@ -11178,21 +11231,21 @@ static char *handle_queue_remove_member(struct ast_cli_entry *e, int cmd, struct
static char *handle_queue_change_priority_caller(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
const char *queuename, *caller;
int priority;
int priority, immediate = 0;
char *res = CLI_FAILURE;
switch (cmd) {
case CLI_INIT:
e->command = "queue priority caller";
e->usage =
"Usage: queue priority caller <channel> on <queue> to <priority>\n"
" Change the priority of a channel on a queue.\n";
"Usage: queue priority caller <channel> on <queue> to <priority> [immediate]\n"
" Change the priority of a channel on a queue, optionally applying the change in relation to existing callers.\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != 8) {
if (a->argc < 8) {
return CLI_SHOWUSAGE;
} else if (strcmp(a->argv[4], "on")) {
return CLI_SHOWUSAGE;
@ -11201,12 +11254,17 @@ static char *handle_queue_change_priority_caller(struct ast_cli_entry *e, int cm
} else if (sscanf(a->argv[7], "%30d", &priority) != 1) {
ast_log (LOG_ERROR, "<priority> parameter must be an integer.\n");
return CLI_SHOWUSAGE;
} else if (a->argc == 9) {
if (strcmp(a->argv[8], "immediate")) {
return CLI_SHOWUSAGE;
}
immediate = 1;
}
caller = a->argv[3];
queuename = a->argv[5];
switch (change_priority_caller_on_queue(queuename, caller, priority)) {
switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
case RES_OKAY:
res = CLI_SUCCESS;
break;