[Sciviews-commits] r310 - in pkg/svSocket: . R inst/etc man
noreply at r-forge.r-project.org
noreply at r-forge.r-project.org
Sat Sep 25 09:31:45 CEST 2010
Author: phgrosjean
Date: 2010-09-25 09:31:45 +0200 (Sat, 25 Sep 2010)
New Revision: 310
Added:
pkg/svSocket/R/socketClientConnection.R
pkg/svSocket/man/socketClientConnection.Rd
Modified:
pkg/svSocket/NAMESPACE
pkg/svSocket/NEWS
pkg/svSocket/R/parSocket.R
pkg/svSocket/R/processSocket.R
pkg/svSocket/R/startSocketServer.R
pkg/svSocket/inst/etc/ReadMe.txt
pkg/svSocket/man/parSocket.Rd
Log:
processSocket() modified to call parseText()
A new socketclientconn R connection is added
A slight modification in parSocket() is also done
Modified: pkg/svSocket/NAMESPACE
===================================================================
--- pkg/svSocket/NAMESPACE 2010-09-25 07:23:55 UTC (rev 309)
+++ pkg/svSocket/NAMESPACE 2010-09-25 07:31:45 UTC (rev 310)
@@ -11,4 +11,7 @@
closeSocketClients,
startSocketServer,
stopSocketServer,
- svTaskCallbackManager)
+ svTaskCallbackManager,
+ socketClientConnection)
+
+S3method(summary, sockclientconn)
\ No newline at end of file
Modified: pkg/svSocket/NEWS
===================================================================
--- pkg/svSocket/NEWS 2010-09-25 07:23:55 UTC (rev 309)
+++ pkg/svSocket/NEWS 2010-09-25 07:31:45 UTC (rev 310)
@@ -4,7 +4,24 @@
* processSocket() now calls parseText() from svMisc >= 0.9-60 instead of Parse().
+* When Echo is TRUE and we are not in hidden mode, results are echoed directly
+ in the R console as they are available, and not any more at the end of the
+ calculation.
+
+* A new type of connection is added: a 'sockclientconn' that allows to redirect
+ output (append or write-only, for the moment) to a SciViews socket client. It
+ is created by using socketClientConnection() and has a specific summary()
+ method. It inherits from a 'sockconn' object and should behave similarly.
+
+* parSocket() has a new argument, clientsocket, that allows to pass the Tcl name
+ of the client's socket. This is required to use socketClientConnection() by
+ providing only the client's name (and thus, the required Tcl socket name is
+ obtained through the property parSocket(....)$clientsocket, if it was
+ previously recorded). The default process function, processSocket() is changed
+ to record the Tcl socket in parSocket() each time a client connects to the
+ server and sends its first command through it.
+
== Changes in svSocket 0.9-49
* Small change in startSocketServer(): the Tcl/Tk callback function now calls
Modified: pkg/svSocket/R/parSocket.R
===================================================================
--- pkg/svSocket/R/parSocket.R 2010-09-25 07:23:55 UTC (rev 309)
+++ pkg/svSocket/R/parSocket.R 2010-09-25 07:31:45 UTC (rev 310)
@@ -1,4 +1,4 @@
-parSocket <- function (client, serverport = 8888, ...)
+parSocket <- function (client, serverport = 8888, clientsocket = client, ...)
{
## Set or get parameters for a given socket client
## No attempt is made to make sure this client exists
@@ -7,6 +7,7 @@
## Create a new environment with default values
e <- new.env(parent = TempEnv())
e$client <- client
+ e$clientsocket <- clientsocket
e$serverport <- serverport
e$prompt <- ":> " # Default prompt
e$continue <- ":+ " # Default continuation prompt
@@ -21,7 +22,11 @@
assign(sc, e, envir = TempEnv())
} else e <- get(sc, envir = TempEnv(), mode = "environment")
## Change or add parameters if they are provided
- args <- list(...)
+ ## There is no reason that serverport changes
+ ## but if a client disconnects and reconnects, the clientsocket may be
+ ## different! But only change if it is sockXXX
+ if (grepl("^sock[0-9]+$", clientsocket)) e$clientsocket <- clientsocket
+ args <- list(...)
if (l <- length(args)) {
change.par <- function (x, val, env) {
if (is.null(x)) return(FALSE) # Do nothing without a valid name
Modified: pkg/svSocket/R/processSocket.R
===================================================================
--- pkg/svSocket/R/processSocket.R 2010-09-25 07:23:55 UTC (rev 309)
+++ pkg/svSocket/R/processSocket.R 2010-09-25 07:31:45 UTC (rev 310)
@@ -1,6 +1,6 @@
processSocket <- function (msg, socket, serverport, ...)
{
- ## This is the default R function that processes a command send by a socket
+ ## This is the default R function that processes a command send by a socket
## client. 'msg' is assumed to be R code contained in a string
## Do we receive a <<<id=myID>>> sequence?
@@ -16,7 +16,8 @@
## Do we receive <<<esc>>>? => break (currently, only break multiline mode)
if (substr(msg, 1, 9) == "<<<esc>>>") {
- pars <- parSocket(client, serverport, code = "") # Reset multiline code
+ ## Reset multiline code and update clientsocket
+ pars <- parSocket(client, serverport, clientsocket = socket, code = "")
msg <- substr(msg, 10, 1000000)
}
@@ -41,34 +42,35 @@
} else if (startmsg == "<<<q>>>") {
msg <- substr(msg, 8, 1000000)
## Remember to indicate disconnection at the end
- parSocket(client, serverport, last = "\n\f")
+ parSocket(client, serverport, clientsocket = socket, last = "\n\f")
} else if (startmsg == "<<<e>>>") {
msg <- substr(msg, 8, 1000000)
## We just configure the server correctly
- parSocket(client, serverport, bare = FALSE, echo = TRUE,
- prompt = ":> ", continue = ":+ ",
- multiline = TRUE, last = "\n\f")
+ parSocket(client, serverport, clientsocket = socket, bare = FALSE,
+ echo = TRUE, prompt = ":> ", continue = ":+ ", multiline = TRUE,
+ last = "\n\f")
## Add a command to the command history
#timestamp("my R command", "", "", quiet = TRUE)
} else if (startmsg == "<<<h>>>") {
msg <- substr(msg, 8, 1000000)
## Do not echo command on the server (silent execution)
hiddenMode <- TRUE
- parSocket(client, serverport, bare = TRUE, last = "\n\f")
+ parSocket(client, serverport, clientsocket = socket, bare = TRUE,
+ last = "\n\f")
} else if (startmsg == "<<<H>>>") {
msg <- substr(msg, 8, 1000000)
## Do not echo command on the server (silent execution with no return)
closeSocketClients(sockets = socket, serverport = serverport)
hiddenMode <- TRUE
returnResults <- FALSE
- parSocket(client, serverport, bare = TRUE)
+ parSocket(client, serverport, clientsocket = socket, bare = TRUE)
} else if (startmsg == "<<<u>>>") {
msg <- substr(msg, 8, 1000000)
## Silent execution, nothing is returned to the client
## (but still echoed to the server)
hiddenMode <- FALSE
returnResults <- FALSE
- parSocket(client, serverport, bare = TRUE)
+ parSocket(client, serverport, clientsocket = socket, bare = TRUE)
}
## Get parameters for the client
@@ -123,7 +125,10 @@
## Is it something to evaluate?
if (length(expr) < 1) return(paste(pars$last, Prompt, sep = ""))
## Correct code,... we evaluate it
- results <- captureAll(expr)
+ ## Something like this should allow for real-time echo in client, but it is too slow
+ ## and it outputs all results at the end...
+ #results <- captureAll(expr, split = Echo, file = socketClientConnection(socket))
+ results <- captureAll(expr, split = Echo)
## Should we run taskCallbacks?
if (!hiddenMode) {
h <- getTemp(".svTaskCallbackManager", default = NULL, mode = "list")
@@ -131,7 +136,7 @@
}
## Collapse and add last and the prompt at the end
results <- paste(results, collapse = "\n")
- if (Echo) cat(results)
+ #if (Echo) cat(results)
if (!returnResults) return("")
Prompt <- if (pars$bare) "" else pars$prompt
results <- paste(results, pars$last, Prompt, sep = "")
Added: pkg/svSocket/R/socketClientConnection.R
===================================================================
--- pkg/svSocket/R/socketClientConnection.R (rev 0)
+++ pkg/svSocket/R/socketClientConnection.R 2010-09-25 07:31:45 UTC (rev 310)
@@ -0,0 +1,74 @@
+socketClientConnection <- function (client, serverport = 8888, socket,
+blocking = FALSE, open = "a", encoding = getOption("encoding"))
+{
+ ## Only accepts "a" or "w" modes currently
+ if (!open %in% c("a", "w"))
+ stop("Only modes \"a\" or \"w\" are currently supported")
+
+ ## Connect to a client of the svSocket server, serving on 'serverport'
+ ## First check that the server is running and is serving 'socket'
+ if (is.null(serverport) || !is.numeric(serverport[1]) || serverport[1] < 1)
+ stop("'serverport' must be a positive integer!")
+ portnum <- round(serverport[1])
+ if (!portnum %in% getSocketServers())
+ stop("There is no currently running socket server on port ",
+ portnum, "\n Start one by using startSocketServer() first")
+ ## If socket is not provided, try to get it from client's infos
+ if (missing(socket))
+ socket <- parSocket(client, serverport)$clientsocket
+ ## Check that 'socket' is a currently opened Tcl socket and is a client
+ res <- try(.Tcl(paste("fconfigure", socket, "-peername")), silent = TRUE)
+ if (inherits(res, "try-error"))
+ stop("This client or this socket is not currently connected")
+ res <- as.character(res)
+ redir <- paste("->", res[1], ":", res[length(res)], sep = "")
+ ## That's OK, we could proceed in opening a socketConnection and redirect it
+ ## to the client's socket...
+# currSocks <- getSocketClientsNames(portnum)
+ sck <- socketConnection(host = "127.0.0.1", port = portnum, server = FALSE,
+ blocking = blocking, open = open, encoding = encoding)
+ ## We need to leave enough time in the background to Tcl to establish the
+ ## connection
+# i <- 0
+# mySock <- character(0)
+# while (length(mySock) < 1 && i < 10) {
+# i <- i + 1
+ .Tcl("update idletasks")
+# Sys.sleep(0.05)
+# currSocks2 <- getSocketClientsNames(portnum)
+# mySock <- currSocks2[!currSocks2 %in% currSocks]
+# }
+# if (length(mySock) < 1) {
+# try(close(sck), silent = TRUE)
+# stop("Unable to connect to the client socket")
+# }
+# mySock <- mySock[1] # Just a precaution
+ ## Now, activate the redirection in Tcl
+# .Tcl(paste("fileevent", mySock, "readable [list sockRedirect", mySock,
+# socket, "]"))
+ ## ... and eliminate this client for the list
+# .Tcl(paste("unset Rserver_", portnum, "(", mySock, ")", sep = ""))
+
+ ## Instruct the socket server to redirect to socket
+ cat(">>>>>>", socket, "\n", sep = "", file = sck)
+ .Tcl("update idletasks")
+
+ ## Finalize the "sockclientconn" object
+# attr(sck, "conn_tclsocket") <- mySock
+ attr(sck, "conn_redirsocket") <- socket
+ attr(sck, "conn_redirection") <- redir
+ class(sck) <- c("sockclientconn", class(sck))
+ return(sck)
+}
+
+## Summary method for sockclientconn object
+summary.sockclientconn <- function (object, ...)
+{
+ obj2 <- object
+ class(obj2) <- "connection"
+ res <- summary(obj2)
+ ## Change description and class
+ res$description <- attr(object, "conn_redirection")
+ res$class <- "sockclientconn"
+ return(res)
+}
Modified: pkg/svSocket/R/startSocketServer.R
===================================================================
--- pkg/svSocket/R/startSocketServer.R 2010-09-25 07:23:55 UTC (rev 309)
+++ pkg/svSocket/R/startSocketServer.R 2010-09-25 07:31:45 UTC (rev 310)
@@ -147,14 +147,20 @@
paste(" #puts \"Close $Rserver_", port, "($sock)\"", sep = ""),
paste(" unset Rserver_", port, "($sock)", sep = ""),
"} else {",
- " global sockPort",
- " global sockClient",
- " global sockMsg",
- paste(" set ::sockPort", port),
- " set ::sockClient $sock",
- " set ::sockMsg $line",
- " SocketServerProc ;# process the command in R",
- "}\n}"),
+ " # Do we have to redirect the connection?",
+ " if {[string compare \">>>>>>sock\" [string range $line 0 9]] == 0} {",
+ " set redirSock [string range $line 6 12]",
+ " fileevent $sock readable [list sockRedirect $sock $redirSock]",
+ paste(" unset Rserver_", port, "($sock)", sep = ""),
+ " } else {",
+ " global sockPort",
+ " global sockClient",
+ " global sockMsg",
+ paste(" set ::sockPort", port),
+ " set ::sockClient $sock",
+ " set ::sockMsg $line",
+ " SocketServerProc ;# process the command in R",
+ "}\n}\n}"),
collapse = "\n")
## if {[gets $sock line] < 0} {return} # To handle incomplete lines!
.Tcl(cmd)
@@ -190,6 +196,20 @@
collapse = "\n")
}
.Tcl(cmd)
+
+ ## Create a Tcl procedure to redirect output (used in socketClientConnection())
+ if (!tclProcExists("sockRedirect")) {
+ cmd <- paste(c("proc sockRedirect {sock tosock} {",
+ "if {[eof $sock] == 1 || [catch {gets $sock line}]} {",
+ " # end of file or abnormal connection drop",
+ " fileevent $sock readable {}",
+ " close $sock",
+ "} else {",
+ " puts $tosock $line",
+ "}\n}"),
+ collapse = "\n")
+ .Tcl(cmd)
+ }
## Create the socket server itself in Tcl (a different one for each port)
## If we want a secure server, use the tls secured socket instead
Modified: pkg/svSocket/inst/etc/ReadMe.txt
===================================================================
--- pkg/svSocket/inst/etc/ReadMe.txt 2010-09-25 07:23:55 UTC (rev 309)
+++ pkg/svSocket/inst/etc/ReadMe.txt 2010-09-25 07:31:45 UTC (rev 310)
@@ -19,7 +19,7 @@
Follow instructions: you can type R commands in the console of the client
application and R returns the results of the calculation. You have no command
line edition, and no command history, but you can test various R commands
-by typing then in the client or pasting them one by one.
+by typing them in the client or pasting them one by one.
To get something closer to a real console, you should display the prompt and
enable multiline mode. You achieve this by configuring the client with:
Modified: pkg/svSocket/man/parSocket.Rd
===================================================================
--- pkg/svSocket/man/parSocket.Rd 2010-09-25 07:23:55 UTC (rev 309)
+++ pkg/svSocket/man/parSocket.Rd 2010-09-25 07:31:45 UTC (rev 310)
@@ -11,7 +11,7 @@
}
\usage{
-parSocket(client, serverport = 8888, ...)
+parSocket(client, serverport = 8888, clientsocket = client, \dots)
}
\arguments{
@@ -21,6 +21,11 @@
fake ones, outside of the socket server, to test your code for instance. }
\item{serverport}{ the port on which the server is running, 8888 by default.
Not important for fake socket client configurations. }
+ \item{clientsocket}{ the Tcl name of the socket where the client is
+ connected. By default, it is the same as \code{client} name, but in case
+ it was modified, do provide a correct \code{clientsocket} string if you
+ want to be able to activate a redirection to it (see
+ \code{socketClientConnection()}). }
\item{\dots}{ the parameters you want to change as named arguments. Non
named arguments are ignored with a warning. If you specify
\code{arg = NULL}, the corresponding variable is deleted from the
@@ -100,7 +105,7 @@
\author{Philippe Grosjean (\email{phgrosjean at sciviews.org})}
\seealso{ \code{\link{startSocketServer}}, \code{\link{sendSocketClients}},
- \code{\link{getSocketClients}} }
+ \code{\link{getSocketClients}}, \code{\link{socketClientConnection}}. }
\examples{
## We use a fake socket client configuration environment
Added: pkg/svSocket/man/socketClientConnection.Rd
===================================================================
--- pkg/svSocket/man/socketClientConnection.Rd (rev 0)
+++ pkg/svSocket/man/socketClientConnection.Rd 2010-09-25 07:31:45 UTC (rev 310)
@@ -0,0 +1,53 @@
+\name{socketClientConnection}
+\alias{socketClientConnection}
+\alias{summary.sockclientconn}
+
+\title{ Open a connection to a SciViews socket client for write access }
+
+\description{
+ A 'sockclientconn' object is created that opens a connection from R to a
+ SciViews socket client (that must be currently connected).
+}
+
+\usage{
+socketClientConnection(client, serverport = 8888, socket, blocking = FALSE,
+ open = "a", encoding = getOption("encoding"))
+
+\method{summary}{sockclientconn}(object, \dots)
+}
+
+\arguments{
+ \item{client}{ the client identification. By default, it is the socket
+ identifier as it appears in \code{getSocketClients()}. The client must be
+ currently connecte. }
+ \item{serverport}{ the port on which the server is running, 8888 by default.
+ This server must be currently running. }
+ \item{socket}{ the Tcl socket name where the targetted client is connected. If
+ not provided, it will be guessed from \code{client}, otherwise,
+ \code{client} is ignored. }
+ \item{blocking}{ logical. Should the connection wait that the data is written
+ before exiting? }
+ \item{open}{ character. How the connection is opened. Currently, only
+ \code{"a"} for append (default) or \code{"w"} for write access are usable. }
+ \item{encoding}{ the name of the encoding to use. }
+ \item{object}{ A 'sockclientconn' object as returned by
+ \code{socketClientConnection()}. }
+ \item{\dots}{ further arguments passed to the method (not used for the
+ moment). }
+}
+
+\value{
+ \code{socketClientConnection()} creates a 'sockclientconn' object redirects
+ text send to it to the SciViews socket server client. It is inherits from a
+ 'sockconn' object (see \code{socketConnection()}), and the only difference is
+ that output is redirected to a Tcl socket corresponding to a given SciViews
+ socket client currently connected.
+}
+
+\author{Philippe Grosjean (\email{phgrosjean at sciviews.org})}
+
+\seealso{ \code{\link[base]{socketConnection}}, \code{\link{sendSocketClients}} }
+
+\keyword{ IO }
+
+\concept{ stateful socket server interprocess communication }
Property changes on: pkg/svSocket/man/socketClientConnection.Rd
___________________________________________________________________
Added: svn:executable
+ *
More information about the Sciviews-commits
mailing list