The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package App::Framework::Extension::Daemon ;

=head1 NAME

App::Framework::Daemon - Daemonize an application

=head1 SYNOPSIS

  use App::Framework '::Daemon' ;


=head1 DESCRIPTION

App::Framework personality that provides a daemonized program (using Net::Server::Daemonize)

B<DOCUMENTATION TO BE COMPLETED>

B<BETA CODE ONLY - NOT TO BE USED IN PRODUCTION SCRIPTS>

=cut

use strict ;
use Carp ;

our $VERSION = "1.000" ;


#============================================================================================
# USES
#============================================================================================
use App::Framework::Core ;
use App::Framework::Extension ;

#============================================================================================
# OBJECT HIERARCHY
#============================================================================================
our @ISA ; 
our $PRIORITY = 100 ;

#============================================================================================
# GLOBALS
#============================================================================================

# Set of script-related default options
my @OPTIONS = (
#	['log|L=s',			'Log file', 		'Specify a log file', ],
#	['v|"verbose"',		'Verbose output',	'Make script output more verbose', ],
#	['debug=s',			'Set debug level', 	'Set the debug level value', ],
#	['h|"help"',		'Print help', 		'Show brief help message then exit'],
#	['man',				'Full documentation', 'Show full man page then exit' ],
#	['dryrun|"norun"',	'Dry run', 			'Do not execute anything that would alter the file system, just show the commands that would have executed'],
) ;

#============================================================================================

=head2 FIELDS

None

=over 4

=cut

my %FIELDS = (
	## Object Data
	'user'		=> 'nobody',
	'group'		=> 'nobody',
	'pid'		=> undef,
) ;

#============================================================================================

=back

=head2 CONSTRUCTOR METHODS

=over 4

=cut

#============================================================================================


=item B<new([%args])>

Create a new App::Framework::Daemon.

The %args are specified as they would be in the B<set> method, for example:

	'mmap_handler' => $mmap_handler

The full list of possible arguments are :

	'fields'	=> Either ARRAY list of valid field names, or HASH of field names with default values 

=cut

sub new
{
	my ($obj, %args) = @_ ;

	my $class = ref($obj) || $obj ;

	## Need Net::Server::Daemonize
	eval "use Net::Server::Daemonize;" ;
	if (@$)
	{
		croak "Sorry. You need to have Net::Server::Daemonize installed to be able to use $class" ;
	}

	## create object dynamically
	my $this = App::Framework::Core->inherit($class, %args) ;

	## Set options
	$this->feature('Options')->append_options(\@OPTIONS) ;
	
	## hi-jack the app function
	$this->extend_fn(
		'app_fn'	=> sub {$this->daemon_run(@_);},
	) ;

	return($this) ;
}



#============================================================================================

=back

=head2 CLASS METHODS

=over 4

=cut

#============================================================================================

#-----------------------------------------------------------------------------

=item B<init_class([%args])>

Initialises the object class variables.

=cut

sub init_class
{
	my $class = shift ;
	my (%args) = @_ ;

	# Add extra fields
	$class->add_fields(\%FIELDS, \%args) ;

	# init class
	$class->SUPER::init_class(%args) ;

}


#============================================================================================

=back

=head2 OBJECT METHODS

=over 4

=cut

#============================================================================================


#----------------------------------------------------------------------------

=item B<daemon_run()>

Daemonize then run the application's app subroutine inside a loop.
 
=cut


sub daemon_run
{
	my $this = shift ;


my $use_net=0;
if ($use_net)
{	

print "Calling daemonize()...\n" ;
	## Daemonize
	Net::Server::Daemonize::daemonize(
	    $this->user,             # User
	    $this->group,            # Group
	    $this->pid,				 # Path to PID file - optional
	);
print "Calling application run...\n" ;
	
	## call application run
	$this->call_extend_fn('app_fn') ;

}

else
{
  ##my $pid = safe_fork();
print "Calling fork()...\n" ;
  my $pid = fork;
  unless( defined $pid ){
    die "Couldn't fork: [$!]\n";
  }


  ### parent process should do the pid file and exit
  if( $pid ){

print "Killing parent..\n" ;
    $pid && exit(0);


  ### child process will continue on
  }else{

	
print "Calling application run...\n" ;
	
	## call application run
	$this->call_extend_fn('app_fn') ;

  }
}



}



# ============================================================================================
# PRIVATE METHODS
# ============================================================================================




# ============================================================================================
# END OF PACKAGE

=back

=head1 DIAGNOSTICS

Setting the debug flag to level 1 prints out (to STDOUT) some debug messages, setting it to level 2 prints out more verbose messages.

=head1 AUTHOR

Steve Price C<< <sdprice at cpan.org> >>

=head1 BUGS

None that I know of!

=cut


1;

__END__