#!/opt/ActivePerl-5.10/bin/perl
use strict;
use FindBin qw($Bin);
use Config::IniFiles;
use Time::Local;
use POSIX 'setsid';
use POSIX 'strftime';
use POSIX ":sys_wait_h";
use Data::Dumper;
use 5.010;
use LWP::UserAgent;
use MIME::Base64;
use File::Basename;
use Storable qw(dclone);
use Redis;
use JSON qw//;
use JSON::PP;
use Encode::KR;
# Author: donnie@astercc.org

my $conf_file = "/etc/astercc.conf" ;
# read parameter from conf file
my $cfg = new Config::IniFiles -file => $conf_file;
if (not defined $cfg) {
	print "Failed to parse $conf_file:\n";
	foreach(@Config::IniFiles::errors) {
		print "Error: $_";
	}
	exit(1);
}
my $debug = trim($cfg->val('system', 'debug'));
my $internal_debug =  trim($cfg->val('system', 'internal_debug'));
my $convert_mp3 = trim($cfg->val('system', 'convert_mp3'));

my $jsons = JSON->new->allow_nonref;
my $ua = new LWP::UserAgent;
$ua->timeout(10);



my $soxcmd = '';
if( -e '/usr/bin/sox'){
	$soxcmd = '/usr/bin/sox';
}elsif( -e '/usr/local/bin/sox'){
	$soxcmd = '/usr/local/bin/sox';
}

my $soxmixcmd = '';
if( -e '/usr/bin/soxmix'){
	$soxmixcmd = '/usr/bin/soxmix';
}elsif( -e '/usr/local/bin/soxmix'){
	$soxmixcmd = '/usr/local/bin/soxmix';
}

my $lamecmd = '';
if( -e '/usr/bin/lame'){
	$lamecmd = '/usr/bin/lame';
}elsif( -e '/usr/local/bin/lame'){
	$lamecmd = '/usr/local/bin/lame';
}
my $pidFile = "/var/run/astcc_post.pid";
if ($ARGV[0] eq '-v'){		# print version
	print "astcc_post version 0.1-160427\n";
	print "copyright \@2016-2016\n";
	exit;
}elsif ($ARGV[0] eq '-k'){
    if (open(MYFILE, $pidFile)) {
	    # here's what to do if the file opened successfully

		my $line = <MYFILE>;
		my $res;
		my $res = `kill -9 $line 2>&1`;
		if ($res eq '') {
			print "astcc_post process: $line is killed. \n";
		}else{
			print "$res \n";
			print "cant kill astcc_post process. \n";
			exit;
		}
		unlink $pidFile;
    }else{
		print "cant find $pidFile. \n";
	}
	exit;
}elsif  ($ARGV[0] eq '-s'){
    if (open(MYFILE, $pidFile)) {
	    # here's what to do if the file opened successfully

		my $line = <MYFILE>;
		my $res;
		my $res = `ps  --pid=$line 2>&1`;
		if ($res =~ /\n(.*)\n/) {
			print "astcc_post status: [start]\n";
		}else{
			print "astcc_post status: [stop]\n";
		}
    }else{
		print "cant find $pidFile, astcc_post may not start \n";
	}
	exit;
}elsif  ($ARGV[0] eq '-h'){
	print "********* astcc_post parameters *********\n";
	print "    -h show help message\n";
	print "    -d start as a daemon\n";
	print "    -s show astcc_post status\n";
	print "    -k stop astcc_post \n";
	print "    -v show astcc_post version \n";
	exit;
}

if (-e $pidFile){
    if (open(MYFILE, $pidFile)) {
		my $line = <MYFILE>;
		my $res;
		my $res = `ps  --pid=$line 2>&1`;
		if ($res =~ /\n(.*)\n/) {
			print "astcc_post is still running. Please stop first.\n"; #If no please del $pidFile \n";
			exit;
		}else{
			unlink $pidFile;
		}
    }
}

if ($ARGV[0] eq '-d'){
	# run background
	my $daemon=1;
	my $pid=&become_daemon;

	open PIDFILE, ">$pidFile" or die "can't open $pidFile: $!\n";
	print PIDFILE $pid;
	close PIDFILE;
}
$SIG{CHLD} = 'IGNORE';

my $rhost = '';
my $rport = '';
my $redis;

if ($cfg->exists('datamover','rhost') && $cfg->exists('datamover','rport')) {
    $rhost=trim($cfg->val('datamover', 'rhost'));
    $rport=trim($cfg->val('datamover', 'rport'));

    $redis = &connect_redis();
    if (!$redis) {
        print("Connection Redis failed, please check the log file for detail.\n");
        exit;
    }
}else{
    print("Please set Redis infomation for datamover section.\n");
    exit;
}
my $i = 0;
while (1){
    if(!$redis){
        $redis = &connect_redis();
    }
    my %taskstr = $redis->BRPOP("PostTask:P",60);
    my $task;
    if(!%taskstr->{'PostTask:P'}){
        next;
    }else{
        $task = $jsons->decode(%taskstr->{'PostTask:P'});
        #$redis->HSET("PostTask:H", $task->{'sessionid'}.$i, %taskstr->{'PostTask:P'});
    }
    #print Dumper($task);
    #print "while start $i\n";
    if (my $child_pid = fork()) {
        #print "I'm parent, my pid=$$, child's pid=$child_pid.\n";
    } else {
        my %postdata;
        my $poststr = '';
        my $posttype = $task->{'posttype'};
        my $postjob = $task->{'postjob'};
        my $postparm = $task->{'postparm'};
        my $monitorbaseurl = $task->{'monitorbaseurl'};
        my $postaddress = $task->{'postaddress'};

        undef $task->{'posttype'};
        undef $task->{'postjob'};
        undef $task->{'postparm'};
        undef $task->{'monitorbaseurl'};
        undef $task->{'postaddress'};

        if($postparm){
            my $filename;
            my $monitorpath = $monitorbaseurl;
            for my $parm (keys %$postparm){
                if(uc($postparm->{$parm}) eq $postparm->{$parm}){
                    %postdata->{$parm} = $postparm->{$parm};
                    $poststr .= '|'.$parm."=".$task->{$postparm->{$parm}};
                }elsif($parm eq 'monitordpath' || $parm eq 'monitorpath' || $parm eq 'record'  ){
                    if($postparm->{$parm} eq 'mix'){
                        my $file = $task->{'monitorfilepath'};
                        if($task->{'basepath'} ne ''){
                            $file =~ s/^\///;

                            if($task->{'basepath'} !~ /\/$/){
                                $task->{'basepath'} .= '/';
                            }

                            $file = $task->{'basepath'}.$file;
                        }
                        $filename = $task->{'monitorfilepath'};
                        my $datadir = dirname $filename;
                        system("mkdir -p /var/www/html/asterCC/app/webroot/getMonitor/$datadir");
                        my $targetfile = "/var/www/html/asterCC/app/webroot/getMonitor/".$filename;
                        if( -f "$file\-in.wav" ){
                            &debug("Found $file\-in.wav");
                            if( -f "$file\-out.wav" ){
                                my $execstr = "$soxcmd -m $file\-in.wav $file\-out.wav -s $targetfile.wav  >/dev/null 2>&1";
                                system($execstr);
                                if($convert_mp3 == 1){
                                    my $execstr = "$lamecmd --cbr -m m -t -F $targetfile.wav $targetfile.mp3  >/dev/null 2>&1";
                                    system($execstr);
                                    if( -f "$targetfile.mp3"){
                                        $monitorpath .= "$filename.mp3";
                                        system("rm -f $targetfile.wav");
                                    }
                                }else{
                                    $monitorpath .= "$filename.wav";
                                }
                            }else{
                                &debug("Can not found $file\-out.wav !!!");
                                $monitorpath = 'NotFound1';
                            }
                        }else{
                            if( -f "$file.wav" ){
                                &debug("$file.wav already mixed !!!!");
                                if($convert_mp3 == 1){
                                    my $execstr = "$soxcmd $file.wav -s $targetfile.wav  >/dev/null 2>&1";
                                    system($execstr);

                                    my $execstr = "$lamecmd --cbr -m m -t -F $targetfile.wav $targetfile.mp3  >/dev/null 2>&1";
                                    system($execstr);
                                    if( -f "$targetfile.mp3"){
                                        $monitorpath .= "$filename.mp3";
                                        system("rm -f $targetfile.wav");
                                    }
                                }else{
                                    $monitorpath .= "$filename.wav";
                                    my $execstr = "$soxcmd $file.wav -s $targetfile.wav  >/dev/null 2>&1";
                                }
                            }elsif( -f "$file.mp3"){
                                my $execstr = "cp -p $file.mp3 $targetfile.mp3";
                                system($execstr);
                                $monitorpath .= "$filename.mp3";
                            }else{
                                &debug("Can not found $file\-in.wav !!!");
                                $monitorpath = 'NotFound2';
                            }
                        }
                        %postdata->{$parm} = $monitorpath;
                        $poststr .= "&".$parm."=".$monitorpath;
                    }else{
                        my $tmppoststr = "$parm='EVENT=GetMonitor&sessionid=$task->{'sessionid'}&calldate=$task->{'calldate'}'";
                        $tmppoststr =~ s/\&/\%26/g;
                        $poststr .= "&".$tmppoststr;
                         %postdata->{$parm} = $tmppoststr;
                    }
                    #$monitorpath =~ s/\&/\%26/g;

                }elsif($parm eq 'ringtime'){
                    my $ringtime = $task->{'duration'} - $task->{'billsec'};
                    $poststr .= "&$parm=".$ringtime;
                    %postdata->{$parm} = $ringtime;
                }else{
                    $poststr .= "&".$parm."=".$task->{$postparm->{$parm}};
                    %postdata->{$parm} = $task->{$postparm->{$parm}};
                }
            }
        }else{
            %postdata = %$task;
        }
        #print Dumper(\%postdata);
        if($posttype eq 'POST'){
            my $rsec = 2;
            my $r = 0;
            while($r < 4){
                $r++;
                &debug("========================".$task->{'sessionid'}."===POST ".$postaddress);
                my $response	= $ua->post($postaddress, \%postdata);
                my $backmsg = $response->decoded_content;
                #print Dumper($response);
                &debug("========================".$task->{'sessionid'}."===Code: ".$response->code." BACKMSG: ".$backmsg);                
                if($response->is_success){
                    if($backmsg ne 'OK'){
                        $redis->lpush("PostTask:P",%taskstr->{'PostTask:P'});
                    }                
                    last;
                }else{
                    if($r == 4){
                        $redis->lpush("PostTask:P",%taskstr->{'PostTask:P'});
                        &debug("========================POST FAILED:".$task->{'sessionid'}.",".$task->{'userdata'}."===Code: ".$response->code." BACKMSG: ".$backmsg);
                        last;
                    }
                    my $sleep = $rsec * $r;
                    if(!$debug){
                        $debug = 1;
                        &debug("========================".$task->{'sessionid'}."===POST ".$postaddress);
                        &debug("========================".$task->{'sessionid'}."===Code: ".$response->code." BACKMSG: ".$backmsg);
                        &debug("Sleep $sleep secs for retry $task->{'sessionid'}");
                    }else{
                        &debug("Sleep $sleep secs for retry $task->{'sessionid'}");
                    }
                    sleep($sleep);
                }
            }
        }else{
            my $rsec = 2;
            my $r = 0;
            while($r < 4){
                $r++;
                &debug("========================".$task->{'sessionid'}."===GET ".$postaddress."?".$poststr);
                my $response	= $ua->get($postaddress."?".$poststr);
                my $backmsg = $response->decoded_content;
                #print Dumper($response);
                &debug("========================".$task->{'sessionid'}."===Code: ".$response->code." BACKMSG: ".$backmsg);
                if($response->is_success){
                    last;
                }else{
                    if($r == 4){
                        &debug("========================POST FAILED:".$task->{'sessionid'}.",".$task->{'userdata'}."===Code: ".$response->code." BACKMSG: ".$backmsg);
                        last;
                    }
                    my $sleep = $rsec * $r;
                    if(!$debug){
                        $debug = 1;
                        &debug("========================".$task->{'sessionid'}."===GET ".$postaddress);
                        &debug("========================".$task->{'sessionid'}."===Code: ".$response->code." BACKMSG: ".$backmsg);
                        &debug("Sleep $sleep secs for retry $task->{'sessionid'}");
                    }else{
                        &debug("Sleep $sleep secs for retry $task->{'sessionid'}");
                    }
                    sleep($sleep);
                }
            }

        }
        exit;
    }
}
exit(0);

sub parse_datetime{
	my $timesrc = shift;
	my $type = shift;
	my $timestr = '';
	if($type eq 'timestamp'){

		my ($tmpYear, $tmpMon, $tmpDay, $tmpHour, $tmpMin, $tmpSec) = split(/[\s\-\:]/,$timesrc);
		$timestr = timelocal($tmpSec, $tmpMin, $tmpHour, $tmpDay, $tmpMon-1, $tmpYear-1900);
	}else{

		my ($sec,$min,$hour,$day,$mon,$year) = localtime($timesrc);
		$year +=1900;
		$mon +=1;
		if ($mon < 10) {
			$mon = "0$mon";
		}
		if ($day<10) {
			$day = "0$day";
		}
		if ($hour<10) {
			$hour = "0$hour";
		}
		if ($min<10) {
			$min = "0$min";
		}
		if ($sec<10) {
			$sec = "0$sec";
		}

		$timestr = $year.'-'.$mon.'-'.$day." $hour:$min:$sec";
	}

	return $timestr;
}

sub trim($)
{
	my $string = shift;
	$string =~ s/^\s+//;
	$string =~ s/\s+$//;
	return $string;
}

sub connect_redis {
    my $result = 1;

    &debug("Connecting to Redis on ".$rhost.":".$rport.";");

    my $rh;
    eval {
        $rh = Redis->new(server => $rhost.':'.$rport, cnx_timeout => 5);
    };

    if ($@) {
		&debug("Redis connection unsuccessful. ".$@);
		$result = 0;
    } else {
        &debug("Redis connection successful.");
        $result = $rh;
    }

    return $result;
}

sub debug{
	my $message = shift;
	my $time=scalar localtime;
	if ($debug > 0) {
		if ($ARGV[0] eq '-d'){		# output to file
			open (HDW,">>$Bin/astcc_post.log");
			print HDW $time," ",$message,"\n";
			close HDW;
		}else{
			print $time," ",$message,"\n";
		}
	}
}

sub become_daemon {
    die "Can't fork" unless defined (my $child = fork);
    exit 0 if $child;#kill父进程
    setsid();
    open( STDIN, "</dev/null" );
    open( STDOUT, ">/dev/null" );
    open( STDERR, ">&STDOUT" );

	$SIG{__WARN__} = sub {
		&debug ("NOTE! " . join(" ", @_));
	};

	$SIG{__DIE__} = sub {
		&debug ("FATAL! " . join(" ", @_));
		unlink $pidFile;
		exit;
	};

	$SIG{HUP} = $SIG{INT} = $SIG{TERM} = sub {
		# Any sort of death trigger results in death of all
		my $sig = shift;
		$SIG{$sig} = 'IGNORE';
		die "killed by $sig\n";
		exit;
	};

    umask(0);
	#$ENV{PATH} = '/bin:/sbin:/usr/bin:/usr/sbin';
    return $$;
}

