]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
mod_callcenter: Add ability to unload/reload/load a queue setting (You still need...
authorMarc Olivier Chouinard <mochouinard@moctel.com>
Fri, 13 Aug 2010 23:15:24 +0000 (19:15 -0400)
committerMarc Olivier Chouinard <mochouinard@moctel.com>
Fri, 13 Aug 2010 23:15:24 +0000 (19:15 -0400)
Note that joining a queue will check for it in the config and load it on the fly... I've used the same system as in mod_voicemail.  Not sure if we should allow this, but just comment it out of the config before unload and it wont be available anymore

src/mod/applications/mod_callcenter/mod_callcenter.c

index 0c629d62bbe6518c768090f76474eee59db4d3c0..ffee20b8ad0d65aeb269d8896537173bc5353ca1 100644 (file)
@@ -404,6 +404,37 @@ static void queue_rwunlock(cc_queue_t *queue)
        }
 }
 
+static void destroy_queue(const char *queue_name, switch_bool_t block)
+{
+       cc_queue_t *queue = NULL;
+       switch_mutex_lock(globals.mutex);
+       if ((queue = switch_core_hash_find(globals.queue_hash, queue_name))) {
+               switch_core_hash_delete(globals.queue_hash, queue_name);
+       }
+       switch_mutex_unlock(globals.mutex);
+
+       if (!queue) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "[%s] Invalid queue\n", queue_name);
+               return;
+       }
+
+       if (block) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "[%s] Waiting for write lock\n", queue->name);
+               switch_thread_rwlock_wrlock(queue->rwlock);
+       } else {
+               if (switch_thread_rwlock_trywrlock(queue->rwlock) != SWITCH_STATUS_SUCCESS) {
+                       /* Lock failed, set the destroy flag so it'll be destroyed whenever its not in use anymore */
+                       switch_set_flag(queue, PFLAG_DESTROY);
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "[%s] queue is in use, memory will be freed whenever its no longer in use\n",
+                                       queue->name);
+                       return;
+               }
+       }
+
+       free_queue(queue);
+}
+
+
 switch_cache_db_handle_t *cc_get_db_handle(cc_queue_t *queue)
 {
        switch_cache_db_connection_options_t options = { {0} };
@@ -437,7 +468,7 @@ cc_queue_t *queue_set_config(cc_queue_t *queue)
           SWITCH _CONFIG_SET_ITEM(item, "key", type, flags, 
           pointer, default, options, help_syntax, help_description)
         */
-       SWITCH_CONFIG_SET_ITEM(queue->config[i++], "strategy", SWITCH_CONFIG_STRING, 0, &queue->strategy, NULL, &queue->config_str_pool, NULL, NULL);
+       SWITCH_CONFIG_SET_ITEM(queue->config[i++], "strategy", SWITCH_CONFIG_STRING, 0, &queue->strategy, "longest-idle-agent", &queue->config_str_pool, NULL, NULL);
        SWITCH_CONFIG_SET_ITEM(queue->config[i++], "moh-sound", SWITCH_CONFIG_STRING, 0, &queue->moh, NULL, &queue->config_str_pool, NULL, NULL);
        SWITCH_CONFIG_SET_ITEM(queue->config[i++], "record-template", SWITCH_CONFIG_STRING, 0, &queue->record_template, NULL, &queue->config_str_pool, NULL, NULL);
        SWITCH_CONFIG_SET_ITEM(queue->config[i++], "time-base-score", SWITCH_CONFIG_STRING, 0, &queue->time_base_score, "queue", &queue->config_str_pool, NULL, NULL);
@@ -1529,11 +1560,23 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
        cc_queue_t *queue = NULL;
        char *sql = NULL;
        char *sql_order_by = NULL;
+       char *queue_name = NULL;
+       char *queue_strategy = NULL;
+       char *queue_record_template = NULL;
        agent_callback_t cbt;
 
        if (!argv[0] || !(queue = get_queue(argv[0]))) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Queue %s not found locally, skip this member\n", argv[0]);
                goto end;
+       } else {
+               queue_name = strdup(queue->name);
+               queue_strategy = strdup(queue->strategy);
+
+               if (queue->record_template) {
+                       queue_record_template = strdup(queue->record_template);
+               }
+
+               queue_rwunlock(queue);
        }
 
        memset(&cbt, 0, sizeof(cbt));
@@ -1543,22 +1586,22 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
        cbt.caller_name = argv[3];
        cbt.joined_epoch = argv[4];
        cbt.queue = argv[0];
-       cbt.strategy = queue->strategy;
-       cbt.record_template = queue->record_template;
-
-       if (!strcasecmp(queue->strategy, "longest-idle-agent") || !strcasecmp(queue->strategy, "roundrobin") /* TODO TMP backward compatibility for taxi dispatch setup */) {
+       cbt.strategy = queue_strategy;
+       cbt.record_template = queue_record_template;
+       
+       if (!strcasecmp(queue->strategy, "longest-idle-agent") || !strcasecmp(queue_strategy, "roundrobin") /* TODO TMP backward compatibility for taxi dispatch setup */) {
                sql_order_by = switch_mprintf("level, agents.last_offered_call, position");
-       } else if (!strcasecmp(queue->strategy, "agent-with-least-talk-time")) {
+       } else if (!strcasecmp(queue_strategy, "agent-with-least-talk-time")) {
                sql_order_by = switch_mprintf("level, agents.talk_time, position");
-       } else if (!strcasecmp(queue->strategy, "agent-with-fewest-calls")) {
+       } else if (!strcasecmp(queue_strategy, "agent-with-fewest-calls")) {
                sql_order_by = switch_mprintf("level, agents.calls_answered, position");
-       } else if (!strcasecmp(queue->strategy, "ring-all")) {
+       } else if (!strcasecmp(queue_strategy, "ring-all")) {
                /* If we set at Trying, who will put it back at Waiting ?? So we just dont change it state for the moment */ 
                /*sql = switch_mprintf("UPDATE members SET state = '%q' WHERE state = '%q' AND uuid = '%q' AND system = 'single_box'", cc_member_state2str(CC_MEMBER_STATE_TRYING), cc_member_state2str(CC_MEMBER_STATE_WAITING), cbt.uuid);
                  cc_execute_sql(NULL, sql, NULL);
                  switch_safe_free(sql);*/
                sql_order_by = switch_mprintf("level, position");
-       } else if(!strcasecmp(queue->strategy, "sequentially-by-agent-order")) {
+       } else if(!strcasecmp(queue_strategy, "sequentially-by-agent-order")) {
                sql_order_by = switch_mprintf("level, position");
        } else {
                /* If the strategy doesn't exist, just fallback to the following */
@@ -1571,7 +1614,7 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
                        " AND (agents.status = '%q' OR agents.status = '%q' OR agents.status = '%q')"
                        " AND agents.state = '%q' AND last_bridge_end < (%ld - wrap_up_time)"
                        " ORDER BY %q",
-                       queue->name,
+                       queue_name,
                        cc_tier_state2str(CC_TIER_STATE_READY), cc_tier_state2str(CC_TIER_STATE_NO_ANSWER),
                        cc_agent_status2str(CC_AGENT_STATUS_AVAILABLE), cc_agent_status2str(CC_AGENT_STATUS_ON_BREAK), cc_agent_status2str(CC_AGENT_STATUS_AVAILABLE_ON_DEMAND),
                        cc_agent_state2str(CC_AGENT_STATE_WAITING), (long) switch_epoch_time_now(NULL),
@@ -1582,9 +1625,11 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
        switch_safe_free(sql);
        switch_safe_free(sql_order_by);
 
-       queue_rwunlock(queue);
-
 end:
+       switch_safe_free(queue_name);
+       switch_safe_free(queue_strategy);
+       switch_safe_free(queue_record_template);
+
        return 0;
 }
 
@@ -1729,7 +1774,7 @@ SWITCH_STANDARD_APP(callcenter_function)
        switch_threadattr_t *thd_attr = NULL;
        switch_memory_pool_t *pool;
        int cc_base_score_int = 0;
-       switch_channel_timetable_t *times = switch_channel_get_timetable(member_channel);
+       switch_channel_timetable_t *times = NULL;
        const char *cc_base_score = switch_channel_get_variable(member_channel, "cc_base_score");
        const char *cc_moh_override = switch_channel_get_variable(member_channel, "cc_moh_override");
        const char *cur_moh = NULL;
@@ -1754,7 +1799,11 @@ SWITCH_STANDARD_APP(callcenter_function)
                goto end;
        }
 
+       /* Make sure we answer the channel before getting the switch_channel_time_table_t answer time */
+       switch_channel_answer(member_channel);
+
        /* Grab the start epoch of a channel */
+       times = switch_channel_get_timetable(member_channel);
        switch_snprintf(start_epoch, sizeof(start_epoch), "%" SWITCH_TIME_T_FMT, times->answered);
 
        /* Add manually imported score */
@@ -1766,7 +1815,6 @@ SWITCH_STANDARD_APP(callcenter_function)
        if (!switch_strlen_zero(start_epoch) && !strcasecmp("system", queue->time_base_score)) {
                cc_base_score_int += (switch_epoch_time_now(NULL) - atoi(start_epoch));
        }
-       switch_channel_answer(member_channel);
 
        if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
                switch_channel_event_set_data(member_channel, event);
@@ -1815,10 +1863,12 @@ SWITCH_STANDARD_APP(callcenter_function)
        /* Playback MOH */
        /* TODO Add DTMF callback support */
        /* TODO add MOH infitite loop */        
-       cur_moh = queue->moh;
        if (cc_moh_override) {
-               cur_moh = cc_moh_override;
+               cur_moh = switch_core_session_strdup(session, cc_moh_override);
+       } else {
+               cur_moh = switch_core_session_strdup(session, queue->moh);
        }
+       queue_rwunlock(queue);
 
        if (cur_moh) {
                switch_ivr_play_file(session, NULL, cur_moh, &args);
@@ -1835,7 +1885,7 @@ SWITCH_STANDARD_APP(callcenter_function)
        if (!switch_channel_up(member_channel)) { /* If channel is still up, it mean that the member didn't hangup, so we should leave the agent alone */
                switch_core_session_hupall_matching_var("cc_member_uuid", uuid, SWITCH_CAUSE_ORIGINATOR_CANCEL);
                sql = switch_mprintf("DELETE FROM members WHERE system = 'single_box' AND uuid = '%q'", uuid);
-               cc_execute_sql(queue, sql, NULL);
+               cc_execute_sql(NULL, sql, NULL);
                switch_safe_free(sql);
 
                if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
@@ -1859,7 +1909,7 @@ SWITCH_STANDARD_APP(callcenter_function)
        } else {
                sql = switch_mprintf("UPDATE members SET state = '%q', bridge_epoch = '%ld' WHERE system = 'single_box' AND uuid = '%q'",
                                cc_member_state2str(CC_MEMBER_STATE_ANSWERED), (long) switch_epoch_time_now(NULL), uuid);
-               cc_execute_sql(queue, sql, NULL);
+               cc_execute_sql(NULL, sql, NULL);
                switch_safe_free(sql);
 
                /* Send Event with queue count */
@@ -1867,8 +1917,6 @@ SWITCH_STANDARD_APP(callcenter_function)
 
        }
 
-       queue_rwunlock(queue);
-
 end:
 
        return;
@@ -2166,7 +2214,42 @@ SWITCH_STANDARD_API(cc_config_api_function)
                        }
                }
        } else if (section && !strcasecmp(section, "queue")) {
-               if (action && !strcasecmp(action, "list")) {
+               if (action && !strcasecmp(action, "load")) {
+                       if (argc-initial_argc < 1) {
+                               stream->write_function(stream, "%s", "-ERR Invalid!\n");
+                               goto done;
+                       } else {
+                               const char *queue_name = argv[0 + initial_argc];
+                               cc_queue_t *queue = NULL;
+                               if ((queue = get_queue(queue_name))) {
+                                       queue_rwunlock(queue);
+                               }
+                               stream->write_function(stream, "%s", "+OK\n");
+                       }
+               } else if (action && !strcasecmp(action, "unload")) {
+                       if (argc-initial_argc < 1) {
+                               stream->write_function(stream, "%s", "-ERR Invalid!\n");
+                               goto done;
+                       } else {
+                               const char *queue_name = argv[0 + initial_argc];
+                               destroy_queue(queue_name, SWITCH_FALSE);
+                               stream->write_function(stream, "%s", "+OK\n");
+
+                       }
+               } else if (action && !strcasecmp(action, "reload")) {
+                       if (argc-initial_argc < 1) {
+                               stream->write_function(stream, "%s", "-ERR Invalid!\n");
+                               goto done;
+                       } else {
+                               const char *queue_name = argv[0 + initial_argc];
+                               cc_queue_t *queue = NULL;
+                               destroy_queue(queue_name, SWITCH_FALSE);
+                               if ((queue = get_queue(queue_name))) {
+                                       queue_rwunlock(queue);
+                               }
+                               stream->write_function(stream, "%s", "+OK\n");
+                       }
+               } else if (action && !strcasecmp(action, "list")) {
                        if (argc-initial_argc < 1) {
                                stream->write_function(stream, "%s", "-ERR Invalid!\n");
                                goto done;