#!/usr/bin/perl
#
# $Id$
#
#	agispeedy daemon
#	Copyright (C) 2005 - 2009, Sun bing.
#	Sun bing <hoowa.sun@gmail.com>
#
#	Freeiris2 -- An Opensource telephony project.
#	Copyright (C) 2005 - 2009, Sun bing.
#	Sun bing <hoowa.sun@gmail.com>
#
#	See http://www.freeiris.org for more information about
#	the Freeiris project.
#
#	This program is free software, distributed under the terms of
#	the GNU General Public License Version 2. See the LICENSE file
#	at the top of the source tree.
#
#	Freeiris2 -- 开源通信系统
#	本程序是自由软件，以GNU组织GPL协议第二版发布。关于授权协议内容
#	请查阅LICENSE文件。
#
#
#

#=================================================================
# initialization preload and construction
#=================================================================
use FindBin qw($Bin);
use lib "$Bin/../lib/";
use base qw(Net::Server::PreFork);
use Time::HiRes qw( gettimeofday );
use DBI;
use Asterisk::AGI;
use Data::Dumper;
use File::Basename;
use Config::IniFiles;
use freeiris::utils;
use strict;
no strict "refs";
use warnings;
our @ISA = qw(Net::Server::PreFork);

#=================================================================
# help print
#=================================================================
my $VERSION=1.2;
if (defined$ARGV[0] && $ARGV[0] eq '--help') {

	print qq~
  agispeedy for freeiris2 project (perfork mode) $VERSION

syntax:
  print help                   :    $0 --help
  run in silence mode[level 0] :    $0 --silence
  run in noise mode[level 4]   :    $0 --verbose
~;

	exit;

} elsif (!defined$ARGV[0] || ($ARGV[0] ne '--silence' && $ARGV[0] ne '--verbose')) {

	print "syntax :    $0 --help\n";

	exit;
}



#=================================================================
# Module Preload
#=================================================================
warn "==========================================================================\n";
warn "agispeedy initilization...\n";

# announce static module struction
our (%STATIC_MODULES,@STATIC_MODULES_LIST);
while (<$Bin/../agimod/*.static>) {
	push(@STATIC_MODULES_LIST,$_);
}
foreach (sort @STATIC_MODULES_LIST) {
	next if (!-e$_);
	
	#file register
my	$mname = basename($_);
	$mname =~ s/\.(.*)//;

	#load static module
	do $_;
	if ($@) {
		warn "Error to preload module : ".$_."\n".$@."\n";
		exit;
	}

	if (!defined *{$mname}{CODE} || !defined *{$mname.'_gpl_license'}{CODE}) {
		warn "Error function '$mname' Not found in $_\n";
		exit;
	}

	#saving
my	@filestat = stat($_);
	$STATIC_MODULES{$mname} = {
		'path'=>$_,
		'regtime'=>time,
		'filestat'=>\@filestat,
		'info'=>&{$mname.'_gpl_license'}(),
	};

	warn "Module perloading - ".basename($_)." - '".$STATIC_MODULES{$mname}{'info'}."' \n";

}

warn "==========================================================================\n";

#running...
__PACKAGE__->run();


exit;


#=================================================================
# Core servery
#=================================================================
#
# subroute : load when server configure
#
sub configure_hook {
my	$self = shift;

	#server options
	$self->{server}->{port} = '127.0.0.1:4573';
	$self->{server}->{user} = 'root';
	$self->{server}->{group} = 'root';
	$self->{server}->{min_servers} = 6;
	$self->{server}->{min_spare_servers} = 2;
	$self->{server}->{max_spare_servers} = 12;
	$self->{server}->{max_servers} = 64;
	$self->{server}->{max_requests} = 512;

	#system logger
my	$runner = basename($0);
	$runner =~ s/\.(.*)//;
	if (defined $ARGV[0] && $ARGV[0] eq '--verbose') {
		$self->{server}->{log_level} = 4;
	} else {
		$self->{server}->{log_level} = 1;
		$self->{server}->{log_file} = "$Bin/../logs/".$runner.".log";
		$self->{server}->{setsid} = 1;
	}

	$self->{server}->{pid_file} = "$Bin/../logs/".$runner.".pid";
	#pid exists checking
	if (-e$self->{server}->{pid_file}) {
	my	$pid_number = `cat $self->{server}->{pid_file}`;
		chomp($pid_number);
		if (-e"/proc/$pid_number/cmdline") {
		my	$pid_cmdline = `cat /proc/$pid_number/cmdline`;
			chomp($pid_cmdline);
		my	$myname = basename($0);
			#pid found
			if ($pid_cmdline =~ /$myname/) {
				$self->logfile(1,"This Daemon Already running: $pid_number");
				$self->logfile(1,"Restarting now...");
				system("kill $pid_number");
				sleep(1);
				system("kill $pid_number");
			
			#pid not this script
			} else {
				unlink($self->{server}->{pid_file});
			}

		#pid not exists
		} else {
			unlink($self->{server}->{pid_file});
		}

		sleep(1);
	}

	#global configure
	my (%fri2conf);
	tie %fri2conf, 'Config::IniFiles', ( -file => "/etc/freeiris2/freeiris.conf" );
	$self->{server}->{fri2conf} = \%fri2conf;

}
#
# subroute : load when child process
#
sub child_init_hook
{
my	$self = shift;

	#global configure
my	(%fri2conf);
	tie %fri2conf, 'Config::IniFiles', ( -file => "/etc/freeiris2/freeiris.conf" );
	$self->{server}->{fri2conf} = \%fri2conf;

	#connect database
	$self->database_pconnect();
}
#
# subroute : input parser like GET / POST in HTML
#
sub process_request {
my	$self = shift;

	# create Asterisk::AGI handle
	$self->{server}{agi} = Asterisk::AGI->new;
my	%input = $self->{server}{agi}->ReadParse();
	$self->{server}{input} = \%input;

	# GET PARSE PARAM
my	%params;
#my	($method, $path) = $input{'request'} =~ m/\/(\w+)\?*([^\/]*)$/;
my  ($method, $path) = $input{'request'} =~ m{/(\w+)\?(.*)$};
	foreach (split(/[&;]/,$path)) {
		my($p,$v) = split('=',$_,2);
		$params{$p} = $v;
	}
	$self->{server}{params} = \%params;
	$self->{server}{method} = $method;
	$self->{server}{path}	= $path;

	#trying from static table
	if (exists($STATIC_MODULES{$method})) {

		$self->logfile(4, "Request-static : $method $input{callerid}-->$input{extension}");

		$self->$method() if($self->can($method));


	} else {

		#trying from dynamic
		if (-e"$Bin/../agimod/$method\.dynamic") {

			$self->logfile(4, "Request-dynamic : $method $input{callerid}-->$input{extension}");

			#load static module
			do "$Bin/../agimod/$method\.dynamic";
			if ($@) {
				$self->logfile(4, "Dynamic Module Error : ".$method." ".$@."");
				$self->{server}{agi}->hangup();
				exit;
			}

			if (!defined *{$method}{CODE} || !defined *{$method.'_gpl_license'}{CODE}) {
				$self->logfile(4, "Dynamic Module Error function '$method' Not found in $method");
				$self->{server}{agi}->hangup();
				exit;
			}

			$self->$method() if($self->can($method));

		#not found
		} else {
			$self->logfile(4, "Request : $method Not Found!");
			$self->{server}{agi}->hangup();
		}

	}

}


#
# subroute : file logger record
#
sub logfile
{
my	$self = shift;
my	$level = shift;
my	$message = shift;
my	$time = localtime();
	$self->log($level,"[$time] [$$] $message");
}
#=================================================================
# services
#=================================================================
#
# subroute : database perisistence connect
#
sub database_pconnect
{
my	$self = shift;

	if (!defined $self->{server}{dbh} || !$self->{server}{dbh}->ping) {

		$self->{server}{dbh} = DBI->connect("DBI:mysql:database=".$self->{server}->{fri2conf}->{'database'}{'dbname'}.
											";host=".$self->{server}->{fri2conf}->{'database'}{'dbhost'}.
											";port=".$self->{server}->{fri2conf}->{'database'}{'dbport'}.
											";mysql_socket=".$self->{server}->{fri2conf}->{'database'}{'dbsock'},
										$self->{server}->{fri2conf}->{'database'}{'dbuser'},
										$self->{server}->{fri2conf}->{'database'}{'dbpasswd'},
										{'RaiseError' => 1});
		$self->logfile(4, "Database Connected!");

	}

return($self->{server}{dbh});
}


