当前位置:   article > 正文

基于freeswitch 自动外呼系统实现(一)_基于freeswith的智能外呼

基于freeswith的智能外呼

原文网址:http://www.luojie1987.com/index.php/post/179.html

 

15年基于freewitch做的自动群呼系统,主要由监听模块,任务外呼模块,及FIFO实现。


1、mod_cctask.c

 
  1. #include <switch.h>  
  2. #include <switch_stun.h>  
  3.  
  4. #define zstr(x) _zstr(x)
  5.  
  6. SWITCH_MODULE_LOAD_FUNCTION(mod_cctask_load);
  7. SWITCH_MODULE_RUNTIME_FUNCTION(mod_cctask_runtime);
  8. SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_cctask_shutdown);
  9. SWITCH_MODULE_DEFINITION(mod_cctask, mod_cctask_load, mod_cctask_shutdown, mod_cctask_runtime);
  10.  
  11. switch_api_interface_t *api_interface;
  12.  
  13. static struct {
  14.     switch_hash_t *caller_orig_hash;
  15.     switch_hash_t *consumer_orig_hash;
  16.     switch_hash_t *bridge_hash;
  17.     switch_hash_t *use_hash;
  18.     switch_mutex_t *use_mutex;
  19.     switch_mutex_t *caller_orig_mutex;
  20.     switch_mutex_t *consumer_orig_mutex;
  21.     switch_mutex_t *bridge_mutex;
  22.     switch_hash_t *fifo_hash;
  23.     switch_mutex_t *mutex;
  24.     switch_mutex_t *sql_mutex;
  25.     switch_memory_pool_t *pool;
  26.     int running;
  27.     switch_event_node_t *node;
  28.     char hostname[256];
  29.     char *dbname;
  30.     char odbc_dsn[1024];
  31.     int node_thread_running;
  32.     switch_odbc_handle_t *master_odbc;
  33.     int threads;
  34.     switch_thread_t *node_thread;
  35.     int debug;
  36.     struct fifo_node *nodes;
  37.     char *pre_trans_execute;
  38.     char *post_trans_execute;
  39.     char *inner_pre_trans_execute;
  40.     char *inner_post_trans_execute;
  41.     switch_sql_queue_manager_t *qm;
  42.     int allow_transcoding;
  43.     switch_bool_t delete_all_members_on_startup;
  44. } globals;
  45.  
  46. struct callback {
  47.     char *buf;
  48.     size_t len;
  49.     int matches;
  50. };
  51. typedef struct callback callback_t;
  52.  
  53.  
  54. struct cc_cctask_call_obj {
  55. char task_id[32];
  56. char gateway[64]; //网关
  57. char exten[64];//分机
  58. char context[64];//context区分
  59. char cid_name[64];//主叫
  60. char cid_num[64];//主叫号码
  61. char fifo_name[64];
  62. };
  63. typedef struct cc_cctask_call_obj cctask_call_obj;
  64.  
  65.  
  66. switch_cache_db_handle_t *cctask_get_db_handle(void)
  67. {
  68.     switch_cache_db_handle_t *dbh = NULL;
  69.     char *dsn;
  70.  
  71.     if (!zstr(globals.odbc_dsn)) {
  72.         dsn = globals.odbc_dsn;
  73.     } else {
  74.         dsn = globals.dbname;
  75.     }
  76.  
  77.     if (switch_cache_db_get_db_handle_dsn(&dbh, dsn) != SWITCH_STATUS_SUCCESS) {
  78.         dbh = NULL;
  79.     }
  80.  
  81.     return dbh;
  82. }
  83.  
  84. static switch_bool_t cctask_execute_sql_callback(switch_mutex_t *mutex, char *sql, switch_core_db_callback_func_t callback, void *pdata)
  85. {
  86.     switch_bool_t ret = SWITCH_FALSE;
  87.     char *errmsg = NULL;
  88.     switch_cache_db_handle_t *dbh = NULL;
  89.  
  90.     if (mutex) {
  91.         switch_mutex_lock(mutex);
  92.     }
  93.  
  94.     if (!(dbh = cctask_get_db_handle())) {
  95.         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB\n");
  96.         goto end;
  97.     }
  98.  
  99.     if (globals.debug > 1) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "sql: %s\n", sql);
  100.  
  101.     switch_cache_db_execute_sql_callback(dbh, sql, callback, pdata, &errmsg);
  102.  
  103.     if (errmsg) {
  104.         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR: [%s] %s\n", sql, errmsg);
  105.         free(errmsg);
  106.     }
  107.  
  108. end:
  109.  
  110.     switch_cache_db_release_db_handle(&dbh);
  111.  
  112.     if (mutex) {
  113.         switch_mutex_unlock(mutex);
  114.     }
  115.  
  116.     return ret;
  117. }
  118.  
  119. char *cc_execute_sql2str(switch_mutex_t *mutex, char *sql, char *resbuf, size_t len)
  120. {
  121.     char *ret = NULL;
  122.     char *errmsg = NULL;
  123.  
  124.     switch_cache_db_handle_t *dbh = NULL;
  125.     if (mutex) {
  126.         switch_mutex_unlock(mutex);
  127.     }
  128.  
  129.     if (!(dbh = cctask_get_db_handle())) {
  130.         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB\n");
  131.         goto end;
  132.     }
  133.  
  134.     ret = switch_cache_db_execute_sql2str(dbh, sql, resbuf, len, NULL);
  135.     if (errmsg) {
  136.         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR: [%s] %s\n", sql, errmsg);
  137.         free(errmsg);
  138.     }
  139.  
  140. end:
  141.     switch_cache_db_release_db_handle(&dbh);
  142.  
  143.     if (mutex) {
  144.         switch_mutex_unlock(mutex);
  145.     }
  146.  
  147.     return ret;
  148. }
  149.  
  150.  
  151. static switch_status_t cc_execute_sql(char *sql, switch_mutex_t *mutex)
  152. {
  153.     switch_cache_db_handle_t *dbh = NULL;
  154.     switch_status_t status = SWITCH_STATUS_FALSE;
  155.  
  156.     if (mutex) {
  157.         switch_mutex_lock(mutex);
  158.     }
  159.     if (!(dbh = cctask_get_db_handle())) {
  160.         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB\n");
  161.         goto end;
  162.     }
  163.  
  164.     status = switch_cache_db_execute_sql(dbh, sql, NULL);
  165.  
  166. end:
  167.  
  168.     switch_cache_db_release_db_handle(&dbh);
  169.  
  170.     if (mutex) {
  171.         switch_mutex_unlock(mutex);
  172.     }
  173.  
  174.     return status;
  175. }
  176.  
  177.  
  178. //从子表获取外呼数据
  179. static int sql2str_callback_run_tables(void *pArg, int argc, char **argv, char **columnNames)
  180. {
  181. struct cc_cctask_call_obj *in = pArg;
  182.  
  183. char *sql;
  184. char *sql_update;
  185.  
  186. sql = switch_mprintf("insert into `uncall_task`.`phone_memory` (`cid_num`, `exten`, `context`, `task_tabke_id`, `task_table`, `gateway`, `fifo_name`, `phone`, `cid_name`) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ",
  187. in->cid_num,
  188. in->exten,
  189. in->context,
  190. argv[0],
  191. in->task_id,
  192. in->gateway,
  193. in->fifo_name,
  194. argv[1],
  195. in->cid_name
  196. );
  197.  
  198. switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "-----> %s \n",sql);
  199. cc_execute_sql(sql,globals.sql_mutex);
  200.     switch_safe_free(sql);
  201. sql_update = switch_mprintf("update `uncall_task`.`ccpaas_run_%s` set `call_time`='%ld' where `id`='%s'  ",
  202. in->task_id,
  203. (long) switch_epoch_time_now(NULL),
  204. argv[0]
  205. );
  206. cc_execute_sql(sql_update, globals.sql_mutex);
  207.     switch_safe_free(sql_update);
  208.  
  209. if(in){
  210. switch_safe_free(in);
  211. }
  212. return 1;
  213. }
  214.  
  215. //写入外呼任务
  216. static int InsterMemoryTables(char *id, char *gateway, char *exten, char *context, char *cid_name, char *cid_num, char *fifo_name, int send_limit){
  217.  
  218. char *sql;
  219. cctask_call_obj *call_obj = (cctask_call_obj*)malloc(sizeof(cctask_call_obj));
  220. switch_copy_string(call_obj->task_id, id, sizeof(call_obj->task_id));
  221. switch_copy_string(call_obj->gateway, gateway, sizeof(call_obj->gateway));
  222. switch_copy_string(call_obj->exten, exten, sizeof(call_obj->exten));
  223. switch_copy_string(call_obj->context, context, sizeof(call_obj->context));
  224. switch_copy_string(call_obj->cid_name, cid_name, sizeof(call_obj->cid_name));
  225. switch_copy_string(call_obj->cid_num, cid_num, sizeof(call_obj->cid_num));
  226. switch_copy_string(call_obj->fifo_name, fifo_name, sizeof(call_obj->fifo_name));
  227. sql = switch_mprintf("select id, phone from uncall_task.ccpaas_run_%s where call_time  is NULL limit %d  ;",id,send_limit);
  228. cctask_execute_sql_callback(globals.sql_mutex, sql, sql2str_callback_run_tables, call_obj);
  229. switch_safe_free(sql);
  230. return 1;
  231. }
  232.  
  233. //获取子表总数
  234. static int GetRunTableCount(char *id){
  235.  
  236. char *sql;
  237. int countNumber = 0;
  238. char res[256] = "0";
  239. sql = switch_mprintf("select count(1) from uncall_task.ccpaas_run_%s where call_time  is NULL;",id);
  240. cc_execute_sql2str(globals.sql_mutex, sql, res, sizeof(res));
  241. switch_safe_free(sql);
  242. if(atoi(res)!=0){
  243. countNumber = atoi(res);
  244. }
  245. return countNumber;
  246. }
  247.  
  248. //获取FIFO成员的总数
  249. static int GetNumberFifoCount(char *fifo_name){
  250.  
  251. char *sql;
  252. int countNumber = 0;
  253. char res[256] = "0";
  254. sql = switch_mprintf("select count(*)  from  uncall_pbx.fifo_outbound where fifo_name='%s';",fifo_name);
  255. cc_execute_sql2str(globals.sql_mutex, sql, res, sizeof(res));
  256. switch_safe_free(sql);
  257. if(atoi(res)!=0){
  258. countNumber = atoi(res);
  259. }
  260. return countNumber;
  261. }
  262.  
  263.  
  264. //获取FIFO成员的总数
  265. static int GetDialogsCount(char *fifo_name){
  266.  
  267. char *sql;
  268. int countNumber = 0;
  269. char res[256] = "0";
  270. sql = switch_mprintf("select count(*) from uncall_pbx.sip_dialogs as ud where ud.contact_user in (select uc.extension from uncall_config.pbx_fifo_extension uc where uc.fifo_name ='%s') ;",fifo_name);
  271. cc_execute_sql2str(globals.sql_mutex, sql, res, sizeof(res));
  272. switch_safe_free(sql);
  273. if(atoi(res)!=0){
  274. countNumber = atoi(res);
  275. }
  276. return countNumber;
  277. }
  278.  
  279. //获取任务内存表数据
  280. static int GetMemoryCount(char *fifo_name){
  281. char *sql;
  282. int countNumber = 0;
  283. char res[256] = "0";
  284. sql = switch_mprintf("select count(1) from uncall_task.phone_memory where fifo_name = '%s';",fifo_name);
  285. cc_execute_sql2str(globals.sql_mutex, sql, res, sizeof(res));
  286. switch_safe_free(sql);
  287. if(atoi(res)!=0){
  288. countNumber = atoi(res);
  289. }
  290. return countNumber;
  291. }
  292.  
  293.  
  294. //获取子表总数
  295. static int UpdateRun(char *id){
  296.  
  297. char *sql;
  298. sql = switch_mprintf("update `uncall_task`.`ccpaas_task` set `task_status`='finish' where `id`='%s' ;",id);
  299.  
  300. cc_execute_sql(sql, globals.sql_mutex);
  301. switch_safe_free(sql);
  302. return 0;
  303. }
  304.  
  305. //获取外呼任务数
  306. static int sql2str_callback(void *pArg, int argc, char **argv, char **columnNames)
  307. {
  308. int fifo_number = 0;
  309. int fifo_number_in_dialogs =0;
  310. int fifo_idle = 0;
  311. int memory = 0;
  312. int send_limit = 0;
  313. int run_table_count = 0;
  314. char id[32]={'\0'};//id
  315. char task_type[64]={'\0'}; //呼叫类型
  316. int  call_max = 0; //最大并发数
  317. char task_cortrol_type[32]={'\0'};//呼叫类型
  318. float task_override = 0;//呼叫系数
  319. char task_day_start[32]={'\0'};//开始时间
  320. char task_day_end[32]={'\0'};//结束时间
  321. char gateway[64]={'\0'}; //网关
  322. char exten[64]={'\0'};//分机
  323. char context[64]={'\0'};//context区分
  324. char cid_name[64]={'\0'};//主叫
  325. char cid_num[64]={'\0'};//主叫号码  
  326. char fifo_name[64]={'\0'};//主叫号码
  327.  
  328. snprintf(id,sizeof(id),"%s",argv[0]);
  329. snprintf(task_type,sizeof(task_type),"%s",argv[3]);
  330. call_max = atoi(argv[6]);
  331. snprintf(task_cortrol_type,sizeof(task_cortrol_type),"%s",argv[7]);
  332. task_override = atof(argv[8]);
  333. snprintf(task_day_start,sizeof(task_day_start),"%s",argv[9]);
  334. snprintf(task_day_end,sizeof(task_day_end),"%s",argv[10]);
  335. snprintf(gateway,sizeof(gateway),"%s",argv[11]);
  336. snprintf(exten,sizeof(exten),"%s",argv[12]);
  337. snprintf(context,sizeof(context),"%s",argv[13]);
  338. snprintf(cid_name,sizeof(cid_name),"%s",argv[14]);
  339. snprintf(cid_num,sizeof(cid_num),"%s",argv[15]);
  340. snprintf(fifo_name,sizeof(fifo_name),"%s",argv[16]);
  341. switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, " listen id ---> %s \n",id);
  342. //判断是否在时间段之内
  343. run_table_count = GetRunTableCount(id);
  344. if(run_table_count<=0){ //没任务更新任务完成
  345. UpdateRun(id);
  346. return 0;
  347. }
  348.  
  349. fifo_number = GetNumberFifoCount(fifo_name);
  350. //判断FIFO中的Dialogs
  351. fifo_number_in_dialogs = GetDialogsCount(fifo_name);
  352. //空闲座席数
  353. fifo_idle = fifo_number - fifo_number_in_dialogs;
  354. if(fifo_idle <= 0){
  355. return 0;
  356. }
  357. memory = GetMemoryCount(fifo_name);
  358. if(0 == strcmp(task_cortrol_type,"i")){//
  359. send_limit = (int)fifo_idle*task_override;
  360. }else{
  361. send_limit = call_max - memory ;
  362. }
  363. if(memory>=call_max){//超过最大并发数
  364. send_limit = 0;
  365. }
  366. if(send_limit>0){//如果需要继续发号码
  367. switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, " send_limit ---> %d \n",send_limit);
  368. InsterMemoryTables(id, gateway, exten, context, cid_name, cid_num, fifo_name,send_limit);
  369. }
  370. return 0;
  371. }
  372.  
  373. static switch_status_t read_config_file(switch_xml_t *xml, switch_xml_t *cfg) {
  374.     
  375. const char *cf = "fifo.conf";
  376.     switch_xml_t settings;
  377.  
  378.     if (!(*xml = switch_xml_open_cfg(cf, cfg, NULL))) {
  379.         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", cf);
  380.         return SWITCH_STATUS_TERM;
  381.     }
  382.     if ((settings = switch_xml_child(*cfg, "settings"))) {
  383.         switch_xml_t param;
  384.         for (param = switch_xml_child(settings, "param"); param; param = param->next) {
  385.             char *var = (char*)switch_xml_attr_soft(param, "name");
  386.             char *val = (char*)switch_xml_attr_soft(param, "value");
  387.             if (!strcasecmp(var, "odbc-dsn") && !zstr(val)) {
  388.                 if (switch_odbc_available() || switch_pgsql_available()) {
  389.                     switch_set_string(globals.odbc_dsn, val);
  390.                 } else {
  391.                     switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ODBC IS NOT AVAILABLE!\n");
  392.                 }
  393. }
  394.         }
  395.     }
  396.     return SWITCH_STATUS_SUCCESS;
  397. }
  398.  
  399. /*
  400. * 获取外呼任务数
  401. */
  402. static void cctask_outbound_sql()
  403. {
  404. char outbound_count[80] = "";
  405. char *sql;
  406. callback_t cbt = { 0 };
  407. cbt.buf = outbound_count;
  408. cbt.len = sizeof(outbound_count);
  409. //sql = switch_mprintf("select id, task_name, task_status, task_type, create_time, create_users, call_max, task_cortrol_type, task_override, task_day_start, task_day_end, gateway, exten, context, cid_name, cid_num, fifo_name ,company_code from uncall_task.ccpaas_task where task_status = 'run'");  
  410. sql = switch_mprintf("select id, task_name, task_status, task_type, create_time, create_users, call_max, task_cortrol_type, task_override, task_day_start, task_day_end, gateway, exten, context, cid_name, cid_num, fifo_name ,company_code from uncall_task.ccpaas_task");
  411. cctask_execute_sql_callback(globals.sql_mutex, sql, sql2str_callback, &cbt);
  412. switch_safe_free(sql);
  413. }
  414.  
  415. static switch_status_t parse_config(switch_bool_t reload)
  416. {
  417. switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "parse config\n");
  418. return SWITCH_STATUS_SUCCESS;
  419. }
  420.  
  421. SWITCH_STANDARD_API(cctask_api_function){
  422. stream->write_function(stream , "CCTASK 1.0 \n");
  423. return SWITCH_STATUS_SUCCESS;
  424. }
  425.  
  426.  
  427. SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_cctask_shutdown){
  428. return SWITCH_STATUS_SUCCESS;
  429. }
  430. SWITCH_MODULE_LOAD_FUNCTION(mod_cctask_load){
  431. //    switch_xml_t xml, cfg;
  432. //    switch_status_t status = SWITCH_STATUS_SUCCESS; 
  433. //    switch_cache_db_handle_t *dbh = NULL; 
  434. switch_api_interface_t *api_interface;
  435. strncpy(globals.hostname, switch_core_get_switchname(), sizeof(globals.hostname) - 1);
  436.  
  437. //    if ((status = read_config_file(&xml, &cfg)) != SWITCH_STATUS_SUCCESS) return status;
  438. //
  439. //    if (!(dbh = cctask_get_db_handle())) {
  440. //            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot open DB!\n"); 
  441. //    }     
  442. /* connect my internal structure to the blank pointer passed to me */  
  443. *module_interface = switch_loadable_module_create_module_interface(pool, modname);
  444. switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "CC-PAAS \n");
  445. //parse_config(SWITCH_FALSE);  
  446. SWITCH_ADD_API(api_interface , "cctask" , "cctask of status", cctask_api_function, "[name]");
  447. /* indicate that the module should continue to be loaded */  
  448. return SWITCH_STATUS_SUCCESS;
  449. }
  450.  
  451.  
  452. //SWITCH_MODULE_RUNTIME_FUNCTION(mod_cctask_runtime){
  453.     while(1) {    
  454.         cctask_outbound_sql();
  455.         switch_yield(1000000);   
  456.     } 
  457. //}
  458. #define switch_set_string(_dst, _src) switch_copy_string(_dst, _src, sizeof(_dst))
  459. #define switch_cache_db_get_db_handle_dsn(_a, _b) _switch_cache_db_get_db_handle_dsn(_a, _b, __FILE__, __SWITCH_FUNC__, __LINE__)
本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号