CDR module push data in realtime engines.
Is it good idea or not?
Example module code:
/*!
* \file
* \brief Custom Realtime CDR records.
*
* \author me
*
*
* \arg See also \ref AstCDR
*
*
* \ingroup cdr_drivers
*/
/*** MODULEINFO
<depend></depend>
<support_level>extended</support_level>
<defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
#include "asterisk/paths.h" /* use ast_config_AST_LOG_DIR */
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/pbx.h"
#include "asterisk/utils.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
AST_MUTEX_DEFINE_STATIC(lock);
static const char config_file[] = "cdr_realtime.conf";
static const char desc[] = "Customizable Realtime CDR Backend";
static const char name[] = "cdr_realtime";
static char RT_Engine[80];
struct ast_variable *fields = NULL;
static void free_config(int reload);
static int load_config(int reload)
{
struct ast_config *cfg;
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
struct ast_variable *var, *first=NULL;
if ((cfg = ast_config_load(config_file, config_flags)) == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
ast_log(LOG_WARNING, "Failed to %sload configuration file. %s\n", reload ? "re" : "", reload ? "" : "Module not activated.");
return -1;
} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
return 0;
}
if (reload) {
free_config(1);
}
// Load main params
ast_copy_string(RT_Engine, ast_variable_retrieve(cfg, "general", "engine"), sizeof(RT_Engine));
ast_verb(3, "CDR Realtime [Engine] start CDR flow to engine %s\n",RT_Engine);
if (var=ast_variable_browse(cfg, "columns")) {
for (; var; var = var->next) {
if(!fields){
fields=ast_variable_new(var->name, var->value,"");
first=fields;
} else {
first->next=ast_variable_new(var->name, var->value,"");
first=first->next;
}
ast_verb(3, "CDR Realtime [add column] %s -> %s\n",var->name, var->value);
}
}
ast_config_destroy(cfg);
return 0;
}
static void free_config(int reload)
{
if(fields){
ast_variables_destroy(fields);
fields=NULL;
}
}
static int write_cdr(struct ast_cdr *cdr)
{
struct ast_variable *var, *values=NULL, *first=NULL;
struct ast_channel *dummy;
char subst_buf[2048];
//RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
if(!fields){
ast_verbose(1, "CDR Realtime - no fields for write in engine, skip CDR update");
return 0;
}
ast_mutex_lock(&lock);
dummy = ast_dummy_channel_alloc();
if (!dummy) {
ast_log(LOG_ERROR, "Unable to allocate channel for variable subsitution.\n");
ast_mutex_unlock(&lock);
return 0;
}
ast_channel_cdr_set(dummy, ast_cdr_dup(cdr));
var=fields;
for (; var; var = var->next) {
pbx_substitute_variables_helper(dummy, var->value, subst_buf, sizeof(subst_buf) - 1);
if(!values){
values=ast_variable_new(var->name,subst_buf,"");
first=values;
} else {
values->next=ast_variable_new(var->name,subst_buf,"");
values=values->next;
}
ast_debug(3, "CDR Realtime [write] %s -> %s\n",var->name, subst_buf);
}
if(first){
ast_store_realtime_fields(RT_Engine,first);
ast_variables_destroy(first);
}
ast_channel_unref(dummy);
ast_mutex_unlock(&lock);
return 0;
}
static int unload_module(void)
{
if (ast_cdr_unregister(name)) {
return -1;
} else {
free_config(0);
return 0;
}
}
static int load_module(void)
{
if (load_config(0)) {
return AST_MODULE_LOAD_DECLINE;
}
if (ast_cdr_register(name, desc, write_cdr)) {
ast_log(LOG_ERROR, "Unable to register custom Realtime CDR handling\n");
free_config(0);
return AST_MODULE_LOAD_DECLINE;
}
return AST_MODULE_LOAD_SUCCESS;
}
static int reload(void)
{
int res = 0;
ast_mutex_lock(&lock);
res = load_config(1);
ast_mutex_unlock(&lock);
return res;
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Realtime CDR Module",
.support_level = AST_MODULE_SUPPORT_EXTENDED,
.load = load_module,
.unload = unload_module,
.reload = reload,
.load_pri = AST_MODPRI_CDR_DRIVER,
.requires = "cdr",
);