[asterisk-users] Asterisk 1.4.30 is slow sending STDIN to AGI script

Gareth Blades list-asterisk at skycomuk.com
Wed Apr 28 09:46:31 CDT 2010


Danny Nicholas wrote:
> Can you post the script?
> 

Yes private stuff is in a separate file. $mode=start works fine but 
answered and completed cause the problem.
I dont know if it is a problem with teh AGI script or just the newer 
asterisk reporting it as an error. It doesnt effect functionality but 
just gives a lot of console output and logging which is undesireable.

Thanks
Gareth



#!/usr/bin/perl -I /var/lib/asterisk/agi-bin/includes

package Asterisk::AGIwrap;
use strict;
use base 'Asterisk::AGI';

sub set_variable
   {
     my ($self, %vars) = @_;
     while (my($var,$val) = each %vars)
       {
         if (!defined($val))
           { warn "AGI->set_variable: not setting '$var' because value 
was undef\n"; next; }
         #warn "AGI->set_variable('$var','$val')\n";
         $self->SUPER::set_variable($var, $val);
       }
   }

package main;
use strict;

our $application = "service_nts_nextgen";
our $subagent = "AGI - $application";
open(OLD_STDERR,">&STDERR") or die "Failed to save STDERR";
open(STDERR,">>/var/log/agi_$application.err") or die "Failed to 
redirect STDERR";

my $settings = require '/var/lib/asterisk/agi-bin/skycom_gw_settings.pl';
our $gatewayID = $settings->{'gatewayID'};
my ($dbname, $dbhost, $dbport, $dbuser, $dbpass) = 
@{%{$settings->{'db'}}}{'name','host','port','user','pass'};

my $db;

eval
   {
     use DBI;
     $db = DBI->connect("DBI:mysql:$dbname:$dbhost:$dbport", $dbuser, 
$dbpass, $settings->{'dbopt'}) || die "Cannot connect to database: 
$DBI::errstr";

     our $AGI = new Asterisk::AGIwrap;

     print STDERR scalar localtime, "  RUNNING:$0 ", (map {"\"$_\" "} 
@ARGV), "\n";
     our $mode = $ARGV[0];
     my %ARG = ();
     if ($mode =~ /mode=(.*)/)
       {
         $ARG{'mode'} = $mode = $1;
         foreach my $arg (@ARGV)
           {
             $arg =~ /^(\w+)=(.*)$/ || next;
             $ARG{$1} = $arg = $2;
           }
       }

     our $not_recognised = 0;
     my $func;

     if ($mode eq "start")
       {
         $func = require 
'/var/lib/asterisk/agi-bin/service_nts_nextgen-start.pl';
         &$func('db'=>$db, 'AGI'=>$AGI, 'settings'=>$settings);
       }

     elsif ($mode eq "answered")
       {
         my $uniqueID = $ARGV[1];
         my $uniqueIDB = $ARGV[2];
         my $destination = $ARGV[3];
         my $destination_type = $ARGV[4];
         my $destination_args = $ARGV[5];
         my $destination_carrier = $ARGV[6];
         $destination =~ s/^00//; # International
         $destination =~ s/^0([1-9]+)/44$1/; # UK
         my $args = {
                 #'destination_type_id' => '"'.$destination_type.'"',
                 'answer_time' => 'NOW()',
                 'answer_epoch' => 'UNIX_TIMESTAMP()',
                 'uniqueIDB' => '"'.$uniqueIDB.'"',
                 'ddi' => '"'.$destination.'"',
                 'carriernameID' => carriernameID($destination_carrier)
                };
         if ($destination_type)
           { $args->{'destination_type_id'} = '"'.$destination_type.'"'; }
         if ($destination_args ne '') { $args->{'destination_args'} = 
'"'.$destination_args.'"'; }
         if (defined($ARG{'params'}))
           { $args->{'extra_params'} = 
$db->quote(urlstr_to_miniserial($ARG{'params'})); }
         &updateCDR($uniqueID,$args,$db);
       }

     elsif ($mode eq "completed")
       {
         my $uniqueID = $ARGV[1];
         my $status = $ARGV[2];
         my $failedpredial = $ARGV[4];
         if ($uniqueID eq "") { $uniqueID = $ARGV[3]; }
         if ($status eq "" && $failedpredial ne "1") { $status = "FAILED"; }
         my $destination_type = ($ARGV[6] =~ /^\d+$/ ? $ARGV[6] : 0);
         my $dest_arg = $ARGV[7];
         my $connect_epoch = $ARGV[8] || 0;

         my $args = {
                 'end_time' => 'NOW()',
                 'end_epoch' => 'UNIX_TIMESTAMP()',
                 'duration' => '(UNIX_TIMESTAMP(NOW()) - 
UNIX_TIMESTAMP(start_time))',
                 'carriernameID' => carriernameID($ARGV[5]),
                 'connect_epoch'=>$connect_epoch,
                 ($destination_type ? 
('destination_type_id'=>$destination_type) : ()),
                };
         if (defined($ARG{'params'}))
           { $args->{'extra_params'} = 
$db->quote(urlstr_to_miniserial($ARG{'params'})); }
         if ($status eq "VOICEMAIL")
           {
             $args->{'destination_type_id'} = 3;
             $status = "ANSWER";
           }
         if ($status eq "ANNOUNCEMENT")
           {
             $args->{'destination_type_id'} = 6;
             $status = "ANSWER";
           }
         if ($destination_type == 1)
           {
             if ($dest_arg =~ /^\d+$/)
               {
                 if ($dest_arg =~ /^00/)
                   { $dest_arg =~ s/^00//; }
                 elsif ($dest_arg =~ /^0[1-9]/)
                   { $dest_arg =~ s/^0/44/; }
                 $args->{'ddi'} = $db->quote($dest_arg);
               }
           }
         elsif ($destination_type > 1)
           { $args->{'destination_args'} = $db->quote($dest_arg); }
         if (!$failedpredial) { $args->{'disposition'} = '"'.$status.'"'; }
         if ($status eq "ANSWER")
           {
             my @existing_updates = keys(%$args);
             $args->{'answer_epoch'} = 
"COALESCE(answer_epoch,UNIX_TIMESTAMP())";
             $args->{'start_epoch'} = "LEAST(start_epoch,answer_epoch)"; 
# } if date puts time back a few seconds, this would cause us to record 
an answer
             $args->{'start_time'} = "FROM_UNIXTIME(start_epoch)"; 
  # } time/epoch earlier than the start time, so fix the start time/epoch
             $args->{'answer_time'} = "FROM_UNIXTIME(answer_epoch)";
             $args->{'end_time'} = "NOW()";
             $args->{'end_epoch'} = "UNIX_TIMESTAMP()";
             $args->{'disposition'} = "'ANSWER'";
             $args->{'duration'} = "end_epoch-start_epoch";
             $args->{'duration_billable'} = "end_epoch-answer_epoch";
             $args->{'.order'} = 
['answer_epoch','answer_time','start_epoch','start_time','end_time','end_epoch','disposition','duration','duration_billable', at existing_updates];
             #$args->{'duration_billable'} = '(UNIX_TIMESTAMP(NOW()) - 
UNIX_TIMESTAMP(answer_time))';
           }
         print STDERR scalar localtime, "  *** CALL COMPLETED: 
".join(',', at ARGV)." ***\n";
         &updateCDR($uniqueID, $args,$db);
       }

     elsif ($mode eq "ida_ddi")
       {
         my ($ddi, $uniqueID) = @ARG{'ddi','uniqueID'};
         $ddi =~ /^\d+$/ || die "Bad ddi '$ddi'\n";
         $func = require 
'/var/lib/asterisk/agi-bin/service_nts_nextgen-start.pl';
         &$func('db'=>$db, 'AGI'=>$AGI, 'settings'=>$settings, 
'selector'=>{'mode'=>'ida_ddi', 'args'=>{'ddi'=>$ddi}});
         ($ddi =~ s/^00//) || ($ddi =~ s/^0([1-9])/44$1/);
         &updateCDR($uniqueID, {'ddi'=>$ddi}, $db);
       }

     elsif ($mode eq "getivr")
       {
         my ($ivrID) = @ARGV[1];
         $ivrID =~ /^\d+$/ || die "Bad ivrID '$ivrID'\n";
         $func = require 
'/var/lib/asterisk/agi-bin/service_nts_nextgen-start.pl';
         &$func('db'=>$db, 'AGI'=>$AGI, 'settings'=>$settings, 
'selector'=>{'mode'=>'ivrmenu', 'args'=>{'ivrID'=>$ivrID}});
       }

     elsif ($mode eq "getivrchoice")
       {
         my ($ivrID, $userchoice) = @ARGV[1,2];
         $ivrID =~ /^\d+$/ || die "Bad ivrID '$ivrID'\n";
         $userchoice =~ /^\d+$/ || die "Bad userchoice '$ivrID'\n";
         $func = require 
'/var/lib/asterisk/agi-bin/service_nts_nextgen-start.pl';
         &$func('db'=>$db, 'AGI'=>$AGI, 'settings'=>$settings, 
'selector'=>{'mode'=>'ivrchoice', 'args'=>{'ivrID'=>$ivrID, 
'userchoice'=>$userchoice}});
       }

   };

print STDERR scalar localtime, "  Gateway $gatewayID app 
error(app=$application, file=$0): $@\n" if $@;

open(STDERR,">&OLD_STDERR") or die "Failed to restore STDERR";

# the end


sub updateCDR
   {
     my ($uniqueid, $args, $db) = @_;

     my @required = ();
     foreach my $field (@required)
       {
         if (!defined($args->{$field}))
           {
             logMessage(10, $subagent, "updateCDR: required field 
missing: ".$field);
             return 0;
           }
       }

     my @updates = ();
     my @update_order = (exists($args->{'.order'}) ? 
@{$args->{'.order'}} : keys %$args);
     delete ($args->{'.order'});
     foreach my $field (@update_order)
       {
         next if !exists($args->{$field});
         push (@updates, "$field=".$args->{$field});
         delete ($args->{$field});
       }
     die "no CDR data" if !@updates;

     my $query = "UPDATE call_detail_log SET ".join(",", at updates)." 
WHERE uniqueID='$uniqueid'";
     print STDERR scalar localtime, "  $query\n";
     $db->do($query);
     return 1;
   }


sub carriernameID
   {
     my $name = shift(@_) || return 0;
     return $db->selectcol_arrayref("SELECT ID FROM 
call_detail_log_enum_carriername WHERE name=?",{},$name)->[0] || eval
       {
         my $rows = $db->do("INSERT INTO 
call_detail_log_enum_carriername SET name=?",{},$name);
         return ($rows > 0 ? $db->{'mysql_insertid'} : 0);
       };
   }


sub urlstr_to_miniserial
   {
     my $urldec = sub { my ($url) = @_; $url =~ s/(\+|%([A-Z0-9]{2}))/$1 
eq '+'?' ':chr(hex($2))/eg; return $url; };
     my $dec_hash = sub { return map { $_ =~ /^(.+?)(=(.*))?$/ && 
(&$urldec($1),&$urldec($3)) } split(/&/,shift(@_)); };
     return join('',map { length($_).':'.$_ } &$dec_hash(@_));
   }





More information about the asterisk-users mailing list