Fugu

 view release on metacpan or  search on metacpan

lib/Fugu/Proxy.pm  view on Meta::CPAN

# Thus the module keeps the Fugu core-Perl load contract, and an
# installation without them still loads it.

use constant {
	PORT_RANGE_START => 8080,
	PORT_RANGE_END   => 8180,
	READY_TIMEOUT    => 30,
	STREAM_CHUNK     => 262144,     # 256KB
	SEND_BUFFER      => 1048576,    # 1MB
};

# Fugu::Proxy->new(%args):
#	cache   => $cache	a Fugu::Proxy::Cache (required)
#	pidfile => $pidfile	a Fugu::Pidfile for the child (required)
#	store   => $store	a Fugu::StateFile that holds the port (required)
#	logfile => $path	where the child's output goes
#	log     => $logger	default: Fugu::Log->default
#	ports   => [$first, $last]	the range to look in
sub new ( $class, %args )
{
	for my $required (qw(cache pidfile store)) {
		die "$required parameter required"
		    unless defined $args{$required};
	}

	my $ports = $args{ports} // [ PORT_RANGE_START, PORT_RANGE_END ];

	return bless {
		cache   => $args{cache},
		pidfile => $args{pidfile},
		store   => $args{store},
		logfile => $args{logfile} // '/dev/null',
		log     => $args{log}     // Fugu::Log->default,
		ports   => $ports,
		meta    => Fugu::Proxy::Meta->new,
		error   => undef,
	}, $class;
}

# $self->cache:
#	Return the cache object.
sub cache ($self)
{
	return $self->{cache};
}

# $self->error: the most recent failure.
sub error ($self)
{
	return $self->{error};
}

# $self->port:
#	Return the port the running proxy listens on, or undef.
sub port ($self)
{
	return $self->{store}->get('proxy_port');
}

# $self->is_running:
#	Report if the proxy child is alive. The check reaps, so a
#	child that became a zombie reads as stopped.
sub is_running ($self)
{
	return $self->{pidfile}->is_running ? 1 : 0;
}

# $self->start:
#	Start the proxy child and wait until it takes connections. The
#	method returns the port, or undef with the reason in ->error.
#	A proxy that already runs returns its port and starts nothing.
sub start ($self)
{
	$self->{error} = undef;

	return $self->port if $self->is_running;

	my $port = $self->_find_free_port;
	unless ( defined $port ) {
		$self->{error} = sprintf 'no free port in %d-%d',
		    @{ $self->{ports} };
		return;
	}

	my $child  = ref $self;
	my $result = Fugu::Process->spawn_perl(
		code      => "use $child; $child->run_child(\@ARGV)",
		args      => [ $port, $self->{cache}->dir ],
		daemonize => 1,
		stdout    => $self->{logfile},
		stderr    => $self->{logfile},
	);
	unless ( $result->{success} ) {
		$self->{error} = "cannot start the proxy: $result->{error}";
		return;
	}

	$self->{pidfile}->write_pid( $result->{pid} );
	$self->{store}->set( proxy_port => $port );

	unless ( $self->wait_ready ) {
		$self->{error} = 'the proxy did not take connections';
		$self->stop;
		return;
	}

	return $port;
}

# $self->stop:
#	Stop the proxy child and forget its port. The method returns 1.
sub stop ($self)
{
	my $pid = $self->{pidfile}->read_pid;
	Fugu::Process->terminate( $pid, grace_period => 5 )
	    if defined $pid;

	$self->{pidfile}->remove;
	$self->{store}->delete('proxy_port');

	return 1;



( run in 1.573 second using v1.01-cache-2.11-cpan-14f38c9f855 )