From duncan at wald.ucdavis.edu  Sun Oct  8 00:34:29 2006
From: duncan at wald.ucdavis.edu (Duncan Temple Lang)
Date: Sat, 07 Oct 2006 15:34:29 -0700
Subject: [Rd] Request to open up getConnection to embedded interface
In-Reply-To: <45280F52.8010704@vanderbilt.edu>
References: <45280F52.8010704@vanderbilt.edu>
Message-ID: <45282B75.8070902@wald.ucdavis.edu>

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


Hi Jeff

  Robert Gentleman and I were just conversing about the need to
make connections part of the general API in some way, be it
as they are now or slightly changed.  It is not just for
the embedded case, but for packages also that we need to be
able to access them from C code and even extend them.
For me, the RCurl and Rcompression packages on omegahat.org
are two clear cases of unnecessarily constrained and complex code.

We need to make much of core R system extensible
at the package level rather than only allowing it to be done
at the R-level.

 So this is on the list of things to do.

  D.



Jeffrey Horner wrote:
> Hello all,
> 
> I would like to request that getConnection() and the struct Rconn 
> declarations be added to the R embedded interface. Here's why.
> 
> It's common in CGI scripts for web applications to direct stdin, stdout, 
> and stderr map to reading from the browser, writing to the browser, and 
> writing to a web log file respectively; very nice and neat. However, 
> things get a little hairy once language interpreters are embedded into 
> web servers.
> 
> For modules like RApache, there are Apache api calls that govern how to 
>   read/write from/to the browser so simple redirection is not feasible.
> 
> With the above request, here is how RApache can alter stdout's behavior:
> 
>      ...
> 
>      Rf_initEmbeddedR(argc, argv); /* initialize R */
> 
> 
>      /* Redirect stdout to apache specific routines */
>      con = getConnection(1);
>      con->private = (void *) apr_pcalloc(p,sizeof(struct ApacheOutpcon));
>      con->text = FALSE; /* allows us to do binary writes */
>      con->vfprintf = mr_stdout_vfprintf;
>      con->write = mr_stdout_write;
>      con->fflush = mr_stdout_fflush;
> 
>      ...
> 
> And here are the definitions of the mr_* functions:
> 
> int mr_stdout_vfprintf(Rconnection con, const char *format, va_list ap){
>      RApacheOutpcon this = con->private;
>      apr_status_t rv;
>      rv = apr_brigade_vprintf(this->brigade, ap_filter_flush, 
> this->filter, format, ap);
>      return (rv == APR_SUCCESS)? 0 : 1;
> }
> int mr_stdout_fflush(Rconnection con){
>      RApacheOutpcon this = con->private;
>      ap_filter_flush(this->brigade,this->filter);
>      /* still need a return value */
> }
> size_t mr_stdout_write(const void *ptr, size_t size, size_t n, 
> Rconnection con){
>      RApacheOutpcon this = con->private;
>      apr_status_t rv;
>      rv = apr_brigade_write(this->brigade, ap_filter_flush, 
> this->filter, (const char *)ptr, size*n);
>      return (rv == APR_SUCCESS)? n : 1;
> }
> 
> (stdin and stderr can be altered in a similar manner, but they not shown).
> 
>   And with that, it's easy to implement simple code to write data to the 
> web browser in various formats:
> 
> dataprovider <- function(r){
> 
>      args <- apache.get_args(r);
>      con <- dbConnect(dbDriver("MySQL"),dbname=db)
>      d <- dbGetQuery(con,"select * from table")
> 
>      if (is.null(args$format)){
>          apache.set_content_type(r,"text/html")
>          if (length(d)>1)
>              HTML(d,file=stdout()) # from R2HTML
>          else
>              cat("<H1>Empty</H1>")
>      } else if (args$format == 'csv'){
>              apache.set_content_type(r,"text/csv")
>              write.csv(d)
>      } else if (args$format == 'xml'){
>              apache.set_content_type(r,"text/xml")
>              writeSDML(d)          # from StatDataML
>      } else if (args$format == 'rds'){
>              apache.set_content_type(r,'application/octet-stream')
>              save(d,file=stdout()) # yes, even this works
>      }
> 
>      dbDisconnect(con)
>      OK
> }
> 
> And of course the output of the above can either be sent to the browser 
> or even to an interactive R session like this:
> 
> load(url("http://example.com/dataprovider?format=rds"))
> 
> or this via StatDataML
> 
> d <- readSDML(file="http://example.com/dataprovider?format=xml")
> 
> or this via read.csv
> 
> d <- read.csv(file=url("http://example.com/dataprovider?format=csv")
> 
> 
> Of course there are other ways to accomplish this, like allowing c code 
> to place c generated connection objects onto the Connection array and 
> then use sink(), but that only works for stdout. Another way is to 
> enhance the default stdin, stdout, stderr reading and writing routines 
> to test for the existence of user provided routines, similar to the way 
> stdout_vfprintf tests R_Outputfile.
> 
> Jeff

- --
Duncan Temple Lang                    duncan at wald.ucdavis.edu
Department of Statistics              work:  (530) 752-4782
4210 Mathematical Sciences Building   fax:   (530) 752-7099
One Shields Ave.
University of California at Davis
Davis,
CA 95616,
USA
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.3 (Darwin)

iD8DBQFFKCt19p/Jzwa2QP4RAqLkAJ47ztIGE2e8ZWiLEuCEUUq4XnqP8ACfZxtN
Teu5CpGmoMXfNVwMs6lw8HQ=
=n4LI
-----END PGP SIGNATURE-----




[Rd] Request to open up getConnection to embedded interface
Duncan Temple Lang