Yeah I know it seems a bit wishful but I have found it very reliable under Windows since at least ActivePerl 5.8 (using 5.12 now)
At any rate I know it can be done just not sure the best way to get it working with JSON::RPC::Server::Daemon.
This package has rather simple startup for the server as follows...
package JSON::RPC::Server::Daemon;
use strict;
use JSON::RPC::Server; # for old Perl 5.005
use base qw(JSON::RPC::Server);
$JSON::RPC::Server::Daemon::VERSION = '0.03';
use Data::Dumper;
sub new {
my $class = shift;
my $self = $class->SUPER::new();
my $pkg;
if( grep { $_ =~ /^SSL_/ } @_ ){
$self->{_daemon_pkg} = $pkg = 'HTTP::Daemon::SSL';
}
else{
$self->{_daemon_pkg} = $pkg = 'HTTP::Daemon';
}
eval qq| require $pkg; |;
if($@){ die $@ }
$self->{_daemon} ||= $pkg->new(@_) or die;
return $self;
}
sub handle {
my $self = shift;
my %opt = @_;
my $d = $self->{_daemon} ||= $self->{_daemon_pkg}->new(@_) or d
+ie;
while (my $c = $d->accept) {
$self->{con} = $c;
while (my $r = $c->get_request) {
$self->request($r);
$self->path_info($r->url->path);
$self->SUPER::handle();
last;
}
$c->close;
}
}
RPC::XML::Server on the other hand is doing stuff that I think is making the signaling work. Only problem is I'm not quite sure what its doing here and even if I was sure what was going on I need advise on possible ways to make it work for the JSON server package.
package RPC::XML::Server;
use 5.006001;
use strict;
use warnings;
use vars qw($VERSION @ISA $INSTANCE $INSTALL_DIR %FAULT_TABLE @XPL_PA
+TH
$IO_SOCKET_SSL_HACK_NEEDED $COMPRESSION_AVAILABLE);
use Carp qw(carp croak);
use AutoLoader 'AUTOLOAD';
use File::Spec;
use IO::Handle;
use HTTP::Status;
use HTTP::Response;
use URI;
use Scalar::Util 'blessed';
use RPC::XML;
use RPC::XML::ParserFactory;
use RPC::XML::Procedure;
....
sub new ## no critic (ProhibitExcessComplexity)
{
my ($class, %args) = @_;
my (
$self, $http, $resp, $host,
$port, $queue, $path, $URI,
$srv_name, $srv_version, $timeout
);
$class = ref($class) || $class;
$self = bless {}, $class;
$srv_version = delete $args{server_version} || $self->version;
$srv_name = delete $args{server_name} || $class;
$self->{__version} = "$srv_name/$srv_version";
if (delete $args{no_http})
{
$self->{__host} = delete $args{host} || q{};
$self->{__port} = delete $args{port} || q{};
}
else
{
require HTTP::Daemon;
$host = delete $args{host} || q{};
$port = delete $args{port} || q{};
$queue = delete $args{queue} || 5;
$http = HTTP::Daemon->new(
Reuse => 1,
($host ? (LocalHost => $host) : ()),
($port ? (LocalPort => $port) : ()),
($queue ? (Listen => $queue) : ())
);
if (! $http)
{
return "${class}::new: Unable to create HTTP::Daemon objec
+t";
}
$URI = URI->new($http->url);
$self->{__host} = $URI->host;
$self->{__port} = $URI->port;
$self->{__daemon} = $http;
}
# Create and store the cached response object for later cloning an
+d use
$resp = HTTP::Response->new();
if (! $resp)
{
return "${class}::new: Unable to create HTTP::Response object"
+;
}
$resp->header( # This is essentially the same string returned b
+y the
# default "identity" method that may be loaded f
+rom a
# XPL file. But it hasn't been loaded yet, and m
+ay not
# be, hence we set it here (possibly from option
+ values)
RPC_Server => $self->{__version},
RPC_Encoding => 'XML-RPC',
# Set any other headers as well
Accept => 'text/xml'
);
$resp->content_type('text/xml');
$resp->code(RC_OK);
$resp->message('OK');
$self->{__response} = $resp;
# Basic (scalar) properties
$self->{__path} = delete $args{path} || q{};
$self->{__started} = 0;
$self->{__method_table} = {};
$self->{__requests} = 0;
$self->{__auto_methods} = delete $args{auto_methods} || 0;
$self->{__auto_updates} = delete $args{auto_updates} || 0;
$self->{__debug} = delete $args{debug} || 0;
$self->{__xpl_path} = delete $args{xpl_path} || [];
$self->{__timeout} = delete $args{timeout} || 10;
$self->{__parser} = RPC::XML::ParserFactory->new(
$args{parser} ? @{delete $args{parser}} : ());
# Set up the default methods unless requested not to
if (! delete $args{no_default})
{
$self->add_default_methods;
}
# Compression support
$self->{__compress} = q{};
if (delete $args{no_compress})
{
$self->{__compress} = q{};
}
else
{
$self->{__compress} = $COMPRESSION_AVAILABLE;
# Add some more headers to the default response object for com
+pression.
# It looks wasteful to keep using the hash key, but it makes i
+t easier
# to change the string in just one place (above) if I have to.
if ($self->{__compress})
{
$resp->header(Accept_Encoding => $self->{__compress});
}
$self->{__compress_thresh} = delete $args{compress_thresh} ||
+4096;
# Yes, I know this is redundant. It's for future expansion/fle
+xibility.
$self->{__compress_re} =
$self->{__compress} ? qr/$self->{__compress}/ : qr/deflate
+/;
}
# Parameters to control the point at which messages are shunted to
+ temp
# files due to size, and where to home the temp files. Start with
+a size
# threshhold of 1Meg and no specific dir (which will fall-through
+to the
# tmpdir() method of File::Spec).
$self->{__message_file_thresh} = delete $args{message_file_thresh}
+ ||
1_048_576;
$self->{__message_temp_dir} = delete $args{message_temp_dir} || q{
+};
# Set up the table of response codes/messages that will be used wh
+en the
# server is sending a controlled error message to a client (as opp
+osed to
# something HTTP-level that is less within our control).
$self->{__fault_table} = {%FAULT_TABLE};
if ($args{fault_code_base})
{
my $base = delete $args{fault_code_base};
# Apply the numerical offset to all (current) error codes
for my $key (keys %{$self->{__fault_table}})
{
if (ref($self->{__fault_table}->{$key}))
{
# A ref is a listref where the first element is the co
+de
$self->{__fault_table}->{$key}->[0] += $base;
}
else
{
$self->{__fault_table}->{$key} += $base;
}
}
}
if ($args{fault_table})
{
my $local_table = delete $args{fault_table};
# Merge any data from this table into the object's fault-table
for my $key (keys %{$local_table})
{
$self->{__fault_table}->{$key} = (ref $local_table->{$key}
+) ?
[ @{$local_table->{$key}} ] : $local_table->{$key};
}
}
# Copy the remaining args over untouched
for (keys %args)
{
$self->{$_} = $args{$_};
}
return $self;
}
...
######################################################################
+#########
#
# Sub Name: server_loop
#
# Description: Enter a server-loop situation, using the accept()
+loop of
# HTTP::Daemon if $self has such an object, or falli
+ng back
# Net::Server otherwise.
#
# The critic disabling is because we may manipulate
+@_
# when using Net::Server.
#
# Arguments: NAME IN/OUT TYPE DESCRIPTION
# $self in ref Object of this class
# %args in hash Additional parameters
+to set up
# before calling the s
+uperclass
# Run method
#
# Returns: string if error, otherwise void
#
######################################################################
+#########
sub server_loop ## no critic (RequireArgUnpacking,ProhibitExcessComple
+xity)
{
my $self = shift;
if ($self->{__daemon})
{
my ($conn, $req, $resp, $reqxml, $respxml, $exit_now, $timeout
+);
my %args = @_;
# Localize and set the signal handler as an exit route
my @exit_signals;
if (exists $args{signal} and $args{signal} ne 'NONE')
{
@exit_signals =
(ref $args{signal}) ? @{$args{signal}} : $args{signal}
+;
}
else
{
push @exit_signals, 'INT';
}
local @SIG{@exit_signals} = (sub { $exit_now++ }) x @exit_sign
+als;
$self->started('set');
$exit_now = 0;
$timeout = $self->{__daemon}->timeout(1);
while (! $exit_now)
{
$conn = $self->{__daemon}->accept;
if ($exit_now)
{
last;
}
if (! $conn)
{
next;
}
$conn->timeout($self->timeout);
$self->process_request($conn);
$conn->close;
undef $conn; # Free up any lingering resources
}
if (defined $timeout)
{
$self->{__daemon}->timeout($timeout);
}
}
else
{
# This is the Net::Server block, but for now HTTP::Daemon is n
+eeded
# for the code that converts socket data to a HTTP::Request ob
+ject
require HTTP::Daemon;
my $conf_file_flag = 0;
my $port_flag = 0;
my $host_flag = 0;
# Disable critic on the C-style for-loop because we need to st
+ep by
# 2 as we check for Net::Server arguments...
for (my $i = 0; $i < @_; $i += 2) ## no critic (ProhibitCStyle
+ForLoops)
{
if ($_[$i] eq 'conf_file') { $conf_file_flag = 1; }
if ($_[$i] eq 'port') { $port_flag = 1; }
if ($_[$i] eq 'host') { $host_flag = 1; }
}
# An explicitly-given conf-file trumps any specified at creati
+on
if (exists($self->{conf_file}) and (!$conf_file_flag))
{
push @_, 'conf_file', $self->{conf_file};
$conf_file_flag = 1;
}
# Don't do this next part if they've already given a port, or
+are
# pointing to a config file:
if (! ($conf_file_flag || $port_flag))
{
push @_, 'port', $self->{port} || $self->port || 9000;
push @_, 'host', $self->{host} || $self->host || q{*};
}
# Try to load the Net::Server::MultiType module
if (! eval { require Net::Server::MultiType; 1; })
{
if ($@)
{
return ref($self) .
"::server_loop: Error loading Net::Server::MultiTy
+pe: $@";
}
}
unshift @RPC::XML::Server::ISA, 'Net::Server::MultiType';
$self->started('set');
# ...and we're off!
$self->run(@_);
}
return;
}
I think that is somehow setting signal handlers in the server_loop function? |