add selfservice xmlrpc facilities (#591)
authorjeff <jeff>
Mon, 6 Aug 2007 08:46:06 +0000 (08:46 +0000)
committerjeff <jeff>
Mon, 6 Aug 2007 08:46:06 +0000 (08:46 +0000)
fs_selfservice/FS-SelfService/MANIFEST
fs_selfservice/FS-SelfService/Makefile.PL
fs_selfservice/FS-SelfService/SelfService/XMLRPC.pm [new file with mode: 0644]
fs_selfservice/FS-SelfService/cgi/xmlrpc.cgi [new file with mode: 0644]
fs_selfservice/FS-SelfService/freeside-selfservice-xmlrpc-server [new file with mode: 0644]

index ebd0d3b..bd142c4 100644 (file)
@@ -2,5 +2,6 @@ Changes
 Makefile.PL
 MANIFEST
 SelfService.pm
+SelfService/XMLRPC.pm
 test.pl
 freeside-selfservice-clientd
index 85c92b4..c078f08 100644 (file)
@@ -5,7 +5,7 @@ WriteMakefile(
     'NAME'             => 'FS::SelfService',
     'VERSION_FROM'     => 'SelfService.pm', # finds $VERSION
     'EXE_FILES'         => [ 'freeside-selfservice-clientd',
-                             #'freeside-selfservice-xmlrpc-server',
+                             'freeside-selfservice-xmlrpc-server',
                            ],
     'INSTALLSCRIPT'     => '/usr/local/sbin',
     'INSTALLSITEBIN'    => '/usr/local/sbin',
diff --git a/fs_selfservice/FS-SelfService/SelfService/XMLRPC.pm b/fs_selfservice/FS-SelfService/SelfService/XMLRPC.pm
new file mode 100644 (file)
index 0000000..71d489b
--- /dev/null
@@ -0,0 +1,87 @@
+package FS::SelfService::XMLRPC;
+
+=head1 NAME
+
+FS::SelfService::XMLRPC - Freeside XMLRPC accessible self-service API
+
+=head1 SYNOPSIS
+
+=head1 DESCRIPTION
+
+Use this API to implement your own client "self-service" module vi XMLRPC.
+
+Each routine described in L<FS::SelfService> is available vi XMLRPC.  All
+values are passed to the selfservice-server in a struct of strings.  The
+return values are in a struct as strings, arrays, or structs as appropriate
+for the values described in L<FS::SelfService>.
+
+=head1 BUGS
+
+-head1 SEE ALSO
+
+L<freeside-selfservice-clientd>, L<freeside-selfservice-server>,L<FS::SelfService>
+
+=cut
+
+use strict;
+use vars qw($DEBUG $AUTOLOAD);
+use FS::SelfService;
+
+$DEBUG = 0;
+$FS::SelfService::DEBUG = $DEBUG;
+
+sub AUTOLOAD {
+  my $call = $AUTOLOAD;
+  $call =~ s/^FS::SelfService::XMLRPC:://;
+  if (exists($FS::SelfService::autoload{$call})) {
+    shift; #discard package name;
+    $call = "FS::SelfService::$call";
+    no strict 'refs';
+    &{$call}(@_);
+  }else{
+    die "No such procedure: $call";
+  }
+}
+
+package SOAP::Transport::HTTP::Daemon;  # yuck
+
+use POSIX qw(:sys_wait_h);
+
+no warnings 'redefine';
+
+sub handle {
+  my $self = shift->new;
+
+  local $SIG{CHLD} = 'IGNORE';
+
+ACCEPT:
+  while (my $c = $self->accept) {
+    
+    my $kid = 0;
+    do {
+      $kid = waitpid(-1, WNOHANG);
+      warn "found kid $kid";
+    } while $kid > 0;
+
+    my $pid = fork;
+    next ACCEPT if $pid;
+
+    if ( not defined $pid ) {
+      warn "fork() failed: $!";
+      $c = undef;
+    } else {
+      while (my $r = $c->get_request) {
+        $self->request($r);
+        $self->SUPER::handle;
+        $c->send_response($self->response);
+      }
+      # replaced ->close, thanks to Sean Meisner <Sean.Meisner@VerizonWireless.com>
+      # shutdown() doesn't work on AIX. close() is used in this case. Thanks to Jos Clijmans <jos.clijmans@recyfin.be>
+      UNIVERSAL::isa($c, 'shutdown') ? $c->shutdown(2) : $c->close(); 
+      $c->close;
+    }
+    exit;
+  }
+}
+
+1;
diff --git a/fs_selfservice/FS-SelfService/cgi/xmlrpc.cgi b/fs_selfservice/FS-SelfService/cgi/xmlrpc.cgi
new file mode 100644 (file)
index 0000000..559ae04
--- /dev/null
@@ -0,0 +1,18 @@
+#!/usr/bin/perl -Tw
+
+use strict;
+use XMLRPC::Transport::HTTP;
+use XMLRPC::Lite; # for XMLRPC::Serializer
+use FS::SelfService::XMLRPC;
+
+my %typelookup = (
+  base64 => [10, sub {$_[0] =~ /[^\x09\x0a\x0d\x20-\x7f]/}, 'as_base64'],
+  dateTime => [35, sub {$_[0] =~ /^\d{8}T\d\d:\d\d:\d\d$/}, 'as_dateTime'],
+  string => [40, sub {1}, 'as_string'],
+);
+my $serializer = new XMLRPC::Serializer(typelookup => \%typelookup);
+XMLRPC::Transport::HTTP::CGI->dispatch_to('FS::SelfService::XMLRPC')
+                            ->serializer($serializer)
+                            ->handle;
+
diff --git a/fs_selfservice/FS-SelfService/freeside-selfservice-xmlrpc-server b/fs_selfservice/FS-SelfService/freeside-selfservice-xmlrpc-server
new file mode 100644 (file)
index 0000000..bd4f83b
--- /dev/null
@@ -0,0 +1,59 @@
+#!/usr/bin/perl -w
+#
+# freeside-selfservice-xmlrpc-server
+#
+
+use strict;
+use Fcntl qw(:flock);
+use POSIX;
+use Getopt::Std;
+use XMLRPC::Transport::HTTP;
+use XMLRPC::Lite; # for XMLRPC::Serializer;
+use FS::SelfService::XMLRPC;
+
+use vars qw( $opt_p $opt_d );
+use vars qw( $DEBUG );
+
+getopts("p:d");
+$DEBUG = $opt_d;
+my $tag = $opt_p ? ':'.$opt_p : '';
+
+my %typelookup = (
+  base64 => [10, sub {$_[0] =~ /[^\x09\x0a\x0d\x20-\x7f]/}, 'as_base64'],
+  dateTime => [35, sub {$_[0] =~ /^\d{8}T\d\d:\d\d:\d\d$/}, 'as_dateTime'],
+  string => [40, sub {1}, 'as_string'],
+);
+my $serializer = new XMLRPC::Serializer(typelookup => \%typelookup);
+
+my $log_file = "/usr/local/freeside/selfservice.xmlrpc$tag.log";
+
+my $pid = fork;
+defined($pid) or die "Can't fork to start: $!";
+print "Started daemon with pid $pid\n" if $pid;
+exit if $pid;
+
+POSIX::setsid();
+open STDIN, "/dev/null" or die "Can't get rid of STDIN";
+open STDOUT, ">/dev/null" or die "Can't get rid of STDOUT";
+open STDERR, ">&STDOUT" or die "Can't get rid of STDERR";
+
+$SIG{__WARN__} = \&_logmsg;
+$SIG{__DIE__} = sub { &_logmsg(@_); exit };
+
+my $daemon = XMLRPC::Transport::HTTP::Daemon
+  ->new(LocalPort => $opt_p ? $opt_p : 8080)
+  ->dispatch_to('FS::SelfService::XMLRPC')
+  ->serializer($serializer);
+
+warn "Handling request at ", $daemon->url, "\n";
+$daemon->handle;
+
+sub _logmsg {
+  chomp( my $msg = shift );
+  my $log = new IO::File ">>$log_file";
+  flock($log, LOCK_EX);
+  seek($log, 0, 2);
+  print $log "[". scalar(localtime). "] [$$] $msg\n";
+  flock($log, LOCK_UN);
+  close $log;
+}