From 9bf2726e1b9e4996d8d10186b27081091e61bd9a Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Wed, 14 Mar 2012 23:26:09 -0500 Subject: [PATCH] FS-3950 --resolve nibblebill changes! --- .../mod_nibblebill/mod_nibblebill.c | 115 +++++++++++------- 1 file changed, 73 insertions(+), 42 deletions(-) diff --git a/src/mod/applications/mod_nibblebill/mod_nibblebill.c b/src/mod/applications/mod_nibblebill/mod_nibblebill.c index cb9942e985..eca9f621c9 100755 --- a/src/mod/applications/mod_nibblebill/mod_nibblebill.c +++ b/src/mod/applications/mod_nibblebill/mod_nibblebill.c @@ -52,19 +52,20 @@ typedef struct { switch_time_t lastts; /* Last time we did any billing */ - float total; /* Total amount billed so far */ + double total; /* Total amount billed so far */ switch_time_t pausets; /* Timestamp of when a pause action started. 0 if not paused */ - float bill_adjustments; /* Adjustments to make to the next billing, based on pause/resume events */ + double bill_adjustments; /* Adjustments to make to the next billing, based on pause/resume events */ + int lowbal_action_executed; /* Set to 1 once lowbal_action has been executed */ } nibble_data_t; typedef struct nibblebill_results { - float balance; + double balance; - float percall_max; /* Overrides global on a per-user level */ - float lowbal_amt; /* ditto */ + double percall_max; /* Overrides global on a per-user level */ + double lowbal_amt; /* ditto */ } nibblebill_results_t; @@ -80,11 +81,11 @@ static struct { switch_mutex_t *mutex; /* Global billing config options */ - float percall_max_amt; /* Per-call billing limit (safety check, for fraud) */ + double percall_max_amt; /* Per-call billing limit (safety check, for fraud) */ char *percall_action; /* Exceeded length of per-call action */ - float lowbal_amt; /* When we warn them they are near depletion */ + double lowbal_amt; /* When we warn them they are near depletion */ char *lowbal_action; /* Low balance action */ - float nobal_amt; /* Minimum amount that must remain in the account */ + double nobal_amt; /* Minimum amount that must remain in the account */ char *nobal_action; /* Drop action */ /* Other options */ @@ -136,7 +137,7 @@ static int nibblebill_callback(void *pArg, int argc, char **argv, char **columnN for (i = 0; i < argc; i++) { if (!strcasecmp(columnNames[i], "nibble_balance")) { - cbt->balance = (float) atof(argv[0]); + cbt->balance = atof(argv[0]); } } @@ -179,15 +180,15 @@ static switch_status_t load_config(void) } else if (!strcasecmp(var, "percall_action")) { set_global_percall_action(val); } else if (!strcasecmp(var, "percall_max_amt")) { - globals.percall_max_amt = (float) atof(val); + globals.percall_max_amt = atof(val); } else if (!strcasecmp(var, "lowbal_action")) { set_global_lowbal_action(val); } else if (!strcasecmp(var, "lowbal_amt")) { - globals.lowbal_amt = (float) atof(val); + globals.lowbal_amt = atof(val); } else if (!strcasecmp(var, "nobal_action")) { set_global_nobal_action(val); } else if (!strcasecmp(var, "nobal_amt")) { - globals.nobal_amt = (float) atof(val); + globals.nobal_amt = atof(val); } else if (!strcasecmp(var, "global_heartbeat")) { globals.global_heartbeat = atoi(val); } @@ -252,6 +253,23 @@ void debug_event_handler(switch_event_t *event) } } +static switch_status_t exec_app(switch_core_session_t *session, const char *app_string) +{ + switch_status_t status; + char *strings[2] = { 0 }; + char *dup; + + if (!app_string) { + return SWITCH_STATUS_FALSE; + } + + dup = strdup(app_string); + switch_assert(dup); + switch_separate_string(dup, ' ', strings, sizeof(strings) / sizeof(strings[0])); + status = switch_core_session_execute_application(session, strings[0], strings[1]); + free(dup); + return status; +} static void transfer_call(switch_core_session_t *session, char *destination) { @@ -292,9 +310,8 @@ static void transfer_call(switch_core_session_t *session, char *destination) free(mydup); } - /* At this time, billing never succeeds if you don't have a database. */ -static switch_status_t bill_event(float billamount, const char *billaccount, switch_channel_t *channel) +static switch_status_t bill_event(double billamount, const char *billaccount, switch_channel_t *channel) { char *sql = NULL, *dsql = NULL; switch_odbc_statement_handle_t stmt = NULL; @@ -306,7 +323,7 @@ static switch_status_t bill_event(float billamount, const char *billaccount, swi if (globals.custom_sql_save) { if (switch_string_var_check_const(globals.custom_sql_save) || switch_string_has_escaped_data(globals.custom_sql_save)) { - switch_channel_set_variable_printf(channel, "nibble_increment", "%f", billamount, SWITCH_FALSE); + switch_channel_set_variable_printf(channel, "nibble_bill", "%f", billamount, SWITCH_FALSE); sql = switch_channel_expand_variables(channel, globals.custom_sql_save); if (sql != globals.custom_sql_save) dsql = sql; } else { @@ -339,14 +356,14 @@ static switch_status_t bill_event(float billamount, const char *billaccount, swi } -static float get_balance(const char *billaccount, switch_channel_t *channel) +static double get_balance(const char *billaccount, switch_channel_t *channel) { char *dsql = NULL, *sql = NULL; nibblebill_results_t pdata; - float balance = 0.00f; + double balance = 0.0; if (!switch_odbc_available()) { - return -1.00f; + return -1.0; } memset(&pdata, 0, sizeof(pdata)); @@ -369,7 +386,7 @@ static float get_balance(const char *billaccount, switch_channel_t *channel) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error running this query: [%s]\n", sql); /* Return -1 for safety */ - balance = -1.00f; + balance = -1.0; } else { /* Successfully retrieved! */ balance = pdata.balance; @@ -391,7 +408,7 @@ static switch_status_t do_billing(switch_core_session_t *session) /* Local vars */ nibble_data_t *nibble_data; switch_time_t ts = switch_micro_time_now(); - float billamount; + double billamount; char date[80] = ""; char *uuid; switch_size_t retsize; @@ -399,9 +416,9 @@ static switch_status_t do_billing(switch_core_session_t *session) const char *billrate; const char *billincrement; const char *billaccount; - float nobal_amt = globals.nobal_amt; - //float lowbal_amt = globals.lowbal_amt; - float balance; + double nobal_amt = globals.nobal_amt; + double lowbal_amt = globals.lowbal_amt; + double balance; if (!session) { /* Why are we here? */ @@ -421,13 +438,13 @@ static switch_status_t do_billing(switch_core_session_t *session) billaccount = switch_channel_get_variable(channel, "nibble_account"); if (!zstr(switch_channel_get_variable(channel, "nobal_amt"))) { - nobal_amt = (float)atof(switch_channel_get_variable(channel, "nobal_amt")); + nobal_amt = atof(switch_channel_get_variable(channel, "nobal_amt")); } - /* + if (!zstr(switch_channel_get_variable(channel, "lowbal_amt"))) { - lowbal_amt = (float)atof(switch_channel_get_variable(channel, "lowbal_amt")); + lowbal_amt = atof(switch_channel_get_variable(channel, "lowbal_amt")); } - */ + /* Return if there's no billing information on this session */ if (!billrate || !billaccount) { return SWITCH_STATUS_SUCCESS; @@ -497,11 +514,15 @@ static switch_status_t do_billing(switch_core_session_t *session) if ((ts - nibble_data->lastts) >= 0) { /* If billincrement is set we bill by it and not by time elapsed */ if (!(switch_strlen_zero(billincrement))) { - float chargedunits = ((int)((ts - nibble_data->lastts) / 1000000) <= (int)atof(billincrement)) ? ((float)atof(billincrement) * 1000000) : ceil((ts - nibble_data->lastts) / ((float)atof(billincrement) * 1000000)) * ((float)atof(billincrement) * 1000000); - billamount = ((float) atof(billrate) / 1000000 / 60) * chargedunits - nibble_data->bill_adjustments; + switch_time_t chargedunits = (ts - nibble_data->lastts) / 1000000 <= atol(billincrement) ? atol(billincrement) * 1000000 : (switch_time_t)(ceil((ts - nibble_data->lastts) / (atol(billincrement) * 1000000.0))) * atol(billincrement) * 1000000; + billamount = (atof(billrate) / 1000000 / 60) * chargedunits - nibble_data->bill_adjustments; + /* Account for the prepaid amount */ + nibble_data->lastts += chargedunits; } else { /* Convert billrate into microseconds and multiply by # of microseconds that have passed since last *successful* bill */ - billamount = ((float) atof(billrate) / 1000000 / 60) * ((ts - nibble_data->lastts)) - nibble_data->bill_adjustments; + billamount = (atof(billrate) / 1000000 / 60) * ((ts - nibble_data->lastts)) - nibble_data->bill_adjustments; + /* Update the last time we billed */ + nibble_data->lastts = ts; } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Billing $%f to %s (Call: %s / %f so far)\n", billamount, billaccount, @@ -521,21 +542,31 @@ static switch_status_t do_billing(switch_core_session_t *session) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failed to log to database!\n"); } } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Just tried to bill %s negative minutes! That should be impossible.\n", - uuid); + if (switch_strlen_zero(billincrement)) + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Just tried to bill %s negative minutes! That should be impossible.\n", uuid); } - /* Update the last time we billed */ - nibble_data->lastts = ts; - /* Save this location */ if (channel) { switch_channel_set_private(channel, "_nibble_data_", nibble_data); /* don't verify balance and transfer to nobal if we're done with call */ if (switch_channel_get_state(channel) != CS_REPORTING && switch_channel_get_state(channel) != CS_HANGUP) { - /* See if this person has enough money left to continue the call */ + balance = get_balance(billaccount, channel); + + /* See if we've achieved low balance */ + if (!nibble_data->lowbal_action_executed && balance <= lowbal_amt) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Balance of %f fell below low balance amount of %f! (Account %s)\n", + balance, lowbal_amt, billaccount); + + if (exec_app(session, globals.lowbal_action) != SWITCH_STATUS_SUCCESS) + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Low balance action didn't execute\n"); + else + nibble_data->lowbal_action_executed = 1; + } + + /* See if this person has enough money left to continue the call */ if (balance <= nobal_amt) { /* Not enough money - reroute call to nobal location */ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Balance of %f fell below allowed amount of %f! (Account %s)\n", @@ -665,7 +696,7 @@ static void nibblebill_resume(switch_core_session_t *session) billrate = switch_channel_get_variable(channel, "nibble_rate"); /* Calculate how much was "lost" to billings during pause - we do this here because you never know when the billrate may change during a call */ - nibble_data->bill_adjustments += ((float) atof(billrate) / 1000000 / 60) * ((ts - nibble_data->pausets)); + nibble_data->bill_adjustments += (atof(billrate) / 1000000 / 60) * ((ts - nibble_data->pausets)); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Resumed billing! Subtracted %f from this billing cycle.\n", (atof(billrate) / 1000000 / 60) * ((ts - nibble_data->pausets))); @@ -711,11 +742,11 @@ static void nibblebill_reset(switch_core_session_t *session) } } -static float nibblebill_check(switch_core_session_t *session) +static double nibblebill_check(switch_core_session_t *session) { switch_channel_t *channel = switch_core_session_get_channel(session); nibble_data_t *nibble_data; - float amount = 0; + double amount = 0; if (!channel) { return -99999; @@ -744,7 +775,7 @@ static float nibblebill_check(switch_core_session_t *session) return amount; } -static void nibblebill_adjust(switch_core_session_t *session, float amount) +static void nibblebill_adjust(switch_core_session_t *session, double amount) { switch_channel_t *channel = switch_core_session_get_channel(session); const char *billaccount; @@ -780,7 +811,7 @@ SWITCH_STANDARD_APP(nibblebill_app_function) if (!zstr(data) && (lbuf = strdup(data)) && (argc = switch_separate_string(lbuf, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) { if (!strcasecmp(argv[0], "adjust") && argc == 2) { - nibblebill_adjust(session, (float) atof(argv[1])); + nibblebill_adjust(session, atof(argv[1])); } else if (!strcasecmp(argv[0], "flush")) { do_billing(session); } else if (!strcasecmp(argv[0], "pause")) { @@ -812,7 +843,7 @@ SWITCH_STANDARD_API(nibblebill_api_function) char *uuid = argv[0]; if ((psession = switch_core_session_locate(uuid))) { if (!strcasecmp(argv[1], "adjust") && argc == 3) { - nibblebill_adjust(psession, (float) atof(argv[2])); + nibblebill_adjust(psession, atof(argv[2])); } else if (!strcasecmp(argv[1], "flush")) { do_billing(psession); } else if (!strcasecmp(argv[1], "pause")) {