#!/usr/bin/perl

eval 'exec /usr/bin/perl  -S $0 ${1+"$@"}'
    if 0; # not running under some shell

use warnings;
use strict;

#use SOAP::Lite ('trace'); 
use SOAP::Lite;

# Copyright 2005 Mark Bucciarelli
# $Id: vsoapd,v 1.8 2005/10/28 04:27:32 perlstalker Exp $

use Pod::Usage;
use Getopt::Long;
use FindBin;
use Config::IniFiles;
use SOAP::Transport::HTTP;

our $REVISION = (split (' ', '$Revision: 1.8 $'))[1];
our $VERSION = "0.2.0";

our $DEBUG = 0;

BEGIN {

    our @etc_dirs = ('/usr/local/etc',
		     '/usr/local/etc/vuser',
		     '/etc',
		     '/etc/vuser',
		     "$FindBin::Bin/../etc",
		     "$FindBin::Bin",
		     "$FindBin::Bin/..",
                     "$FindBin::Bin/vuser",
                     "$FindBin::Bin/../vuser",
                     "$FindBin::Bin/../etc/vuser"
                     );
}

use vars qw(@etc_dirs);

use lib (map { "$_/extensions" } @etc_dirs);
use lib (map { "$_/lib" } @etc_dirs);

use VUser::ExtLib;
use VUser::ExtHandler;
use VUser::SOAP;

use Config;
defined $Config{sig_name} || die "No sigs?";
my (%signo, @signame, $i);
$i = 0;
foreach my $name (split(' ', $Config{sig_name})) {
    $signo{$name} = $i;
    $signame[$i] = $name;
    $i++;
}

my $config_file;
for my $etc_dir (@etc_dirs)
{
    if (-e "$etc_dir/vuser.conf") {
	$config_file = "$etc_dir/vuser.conf";
	last;
    }
}

if (not defined $config_file) {
    die "Unable to find a vuser.conf file in ".join (", ", @etc_dirs).".\n";
}

my %cfg;
tie %cfg, 'Config::IniFiles', (-file => $config_file);

$DEBUG = VUser::ExtLib::strip_ws($cfg{'vuser'}{'debug'}) || 0;
$DEBUG = VUser::ExtLib::check_bool($DEBUG) unless $DEBUG =~ /^\d+$/;
my $debug = $DEBUG;

print "vsoapd $VERSION $REVISION\n" if $debug;

my $pid_file = VUser::ExtLib::strip_ws($cfg{vsoapd}{'pid file'});
$pid_file = '/var/run/vsoapd.pid' unless $pid_file;

#$SIG{INT} = sub { unlink $pid; exit 0; };

my $cmd = shift;
if (not defined $cmd or $cmd eq 'start') {
} elsif ($cmd eq 'stop') {
    my $old_pid = get_old_pid($pid_file);
    print "Sending signal $signo{INT} to pid $old_pid\n" if $debug;
    kill $signo{INT}, $old_pid;
    unlink $pid_file;
    exit;
} elsif ($cmd eq 'restart') {
    my $old_pid = get_old_pid($pid_file);
    kill $signo{INT}, $old_pid;
} else {
    die "Unknown command $cmd\n";
}

# We will be the child after daemonize() is called.
my $pid = daemonize();
if ($pid != 0) {
    open PID, ">$pid_file" or die "Can't write to PID file: $!\n";
    print PID $pid;
    close PID;
    exit;
}

my $eh = new VUser::ExtHandler (\%cfg);

# This is really ugly and there should be a better way of doing this.
VUser::SOAP::init($eh, %cfg);

# don't die on 'Broken pipe' or Ctrl-C
#$SIG{PIPE} = $SIG{INT} = 'IGNORE';

my $port = VUser::ExtLib::strip_ws($cfg{vsoapd}{localport});
$port = 8000 unless defined $port;

my $daemon = SOAP::Transport::HTTP::Daemon
  # if you do not specify LocalAddr then you can access it with 
  # any hostname/IP alias, including localhost or 127.0.0.1. 
  # if do you specify LocalAddr in ->new() then you can only access it 
  # from that interface. -- Michael Percy <mpercy@portera.com>
#  -> new (LocalAddr => 'localhost', LocalPort => 8080) 
  -> new (LocalPort => $port) 
  # you may also add other options, like 'Reuse' => 1 and/or 'Listen' => 128

  # specify list of objects-by-reference here 
  #-> objects_by_reference(qw(My::PersistentIterator My::SessionIterator My::Chat))
  -> objects_by_reference(qw(VUser::SOAP))

  # specify path to My/Examples.pm here
  #-> dispatch_to('/Your/Path/To/Deployed/Modules', 'Module::Name', 'Module::method') 
  -> dispatch_to('VUser::SOAP')

  # enable compression support
  -> options({compress_threshold => 10000})
;
print "Contact to vsoapd server at ", $daemon->url, "\n" if $debug;
$daemon->handle;

unlink $pid_file or warn "Unable to remove $pid_file: $!\n";
eval { $eh->cleanup(%cfg); };

sub daemonize
{
    my $pid = $$;

    return $pid if $DEBUG; # Don't daemonize if we're in debug mode.

    if ($pid = fork) {
	$SIG{CHLD} = "INGORE";
	# exit;
    } elsif ($pid == 0) {
    } else {
	die "Unable to daemonize: $!";
    }

    return $pid;
}

sub get_old_pid
{
    my $file = shift;
    my $pid = undef;
    open (PID, $file) or die "Unable to get pid. vsoapd not running? $!\n";
    $pid  = <PID>;
    close PID;
    return $pid;
}

__END__

=head1 NAME

vsoapd - vuser SOAP daemon.

=head1 SYNOPSIS

vsoapd [start|restart|stop]

=head1 OPTIONS

=head1 DESCRIPTION

=head1 BUGS

=head1 SEE ALSO

=head1 AUTHOR

Randy Smith <perlstalker@gmail.com>

=head1 LICENSE
 
 This file is part of vuser.
 
 vuser is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.
 
 vuser is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with vuser; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

=cut
