Olli Hollmen
and 1 contributors

NAME

JRPC::CGI - JSON-RPC 2.0 Processing for CGI and HTTP::Server::Simple::CGI

DESCRIPTION

This package provides JSON-RPC 2.0 services processor for 2 runtimes based on:

  • CGI (CGI.pm) Plain old CGI scripting (or mod_perl ModPerl::Registry mode)

  • HTTP::Server::Simple::CGI - a fast and lightweight runtime with a Perl embedded httpd (web server) module.

HTTP::Server::Simple::CGI is especially interesting for doing distributed computation over the http.

METHODS

Because of the rudimentary nature of CGI (in both good and bad), the JRPC::CGI::handle_cgi($cgi) is to be called explicitly in code (as CGI is not hosted by sophisticated server).

The service method JRPC::CGI::handle_simple_server_cgi($server, $cgi); for HTTP::Server::Simple::CGI can be aliased to local package's handle_request method, which is the request handling method for HTTP::Server::Simple framework (similar to mod_perl's and Nginx's handler($r) method).

JRPC::CGI::handle_cgi($cgi)

Traditional CGI Handler for JRPC. Example CGI wrapper:

   #!/usr/bin/perl
   use CGI;
   use CGI::Carp qw/fatalsToBrowser warningsToBrowser/;
   use JRPC::CGI;
   use SvcTest; # Load Service package
   my $cgi = CGI->new();
   # Process request. Reports all errors to Client as a JSON-RPC error (fault) response.
   JRPC::CGI::handle_cgi($cgi);
   exit(0);
   
   # This "Service Package" could (and should) be in a separate file (SvcTest.pm).
   # It will be called back by JRPC.
   package SvcTest;
   use Scalar::Util ('reftype');
   # Simpliest possible service:
   # - reflect/echo 'params' (of request) to 'result' (of response)
   # - Framework will take care of request parsing and response serialization
   # - On validation errors, Framework will turn a Perl exception to a JSON-RPC fault.
   # Call this by: ..., "method": "Test.echo", ...
   sub echo {
      my ($p, $jrpc) = @_;
      # Validate, require $p to be HASH (ref).
      # Framework will convert exceptions to JSON-RPC Fault
      if (reftype($p) ne 'HASH') {die("param was not found to be a JSON Object");}
      return($p);
   }
   1;

JRPC::CGI::handle_simple_server_cgi($server, $cgi);

 Wrapper for intercepting a request to HTTP::Server::Simple::CGI.
 Alias this as a handle_request() in your package implementing
 HTTP::Server::Simple::CGI. Example:

   #!/usr/bin/perl
   {
   package MyJRPC;
   use HTTP::Server::Simple::CGI;
   use base 'HTTP::Server::Simple::CGI';
   # Reuse handle_simple_server_cgi, assign as local alias.
   *handle_request = \&JRPC::CGI::handle_simple_server_cgi;
   }
   my $port = $ENV{'HTTP_SIMPLE_PORT'} || 8080;
   my $pid = MyWebServer->new($port);
   #my $pid = MyWebServer->new($port)->background();
   
   print "Use 'kill $pid' to stop server (on port $port).\n";

RUNNING SERVER IN THREAD

To be able to run server in thread and to be able to terminate the thread, use the following idiom:

   # Server thread as anonymous sub. Pass port to run at.
   my $runmyserver = sub {
     my ($port) = @_;
     # Use signaling to kill thread
     $SIG{'KILL'} = sub { threads->exit(); };
     # Run in the same process, NOT spawning a sub process.
     MyServer->new($port)->run();
   };
   
   my $thr = threads->create($runmyserver, $port);
   # ...
   # Much later ... terminate server as no more needed.
   $thr->kill('KILL')->detach();
   # This main thread should continue / survive beyond this point ...

HINTS

JSON-RPC is not a domain for obsessed print(); debugging folks. Printing to STDOUT messes up the JSON-RPC response output. The returned data structure gets automatically converted to a successful JSON-RPC Response (data goes into 'result' member). Any fatal errors thrown as Perl exceptions get automatically converted to a valid JSON-RPC exception / fault (member 'error', and optionally to logs). Any diagnostic messaging goes to response or logs (or both), NOT STDOUT.

TODO

  • Private package (file) for ServerSimple (with direct default handler handle_request())?

  • In private package use HTTP::Server::Simple::CGI (and inherit from it)