diff --git a/DESCRIPTION b/DESCRIPTION index 01073da..fff8a59 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -36,7 +36,7 @@ License: LGPL (>= 2.1) URL: https://github.com/datashield/DSI/, https://datashield.github.io/DSI/, https://datashield.org/ BugReports: https://github.com/datashield/DSI/issues -RoxygenNote: 7.3.2 +RoxygenNote: 7.3.3 Encoding: UTF-8 Collate: 'DSObject.R' @@ -45,6 +45,7 @@ Collate: 'DSI-package.R' 'DSLoginBuilder.R' 'DSResult.R' + 'DSSession.R' 'datashield.aggregate.R' 'datashield.assign.R' 'datashield.connections.R' @@ -53,6 +54,7 @@ Collate: 'datashield.list.R' 'datashield.login.R' 'datashield.logout.R' + 'datashield.sessions.R' 'datashield.status.R' 'datashield.symbol.R' 'datashield.workspace.R' diff --git a/NAMESPACE b/NAMESPACE index be40a13..3a434f6 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -21,6 +21,7 @@ export(datashield.profiles) export(datashield.resource_status) export(datashield.resources) export(datashield.rm) +export(datashield.sessions) export(datashield.symbols) export(datashield.table_status) export(datashield.tables) @@ -37,9 +38,11 @@ export(dsDisconnect) export(dsFetch) export(dsGetInfo) export(dsHasResource) +export(dsHasSession) export(dsHasTable) export(dsIsAsync) export(dsIsCompleted) +export(dsIsReady) export(dsKeepAlive) export(dsListMethods) export(dsListPackages) @@ -52,11 +55,14 @@ export(dsRestoreWorkspace) export(dsRmSymbol) export(dsRmWorkspace) export(dsSaveWorkspace) +export(dsSession) +export(dsStateMessage) export(newDSLoginBuilder) exportClasses(DSConnection) exportClasses(DSDriver) exportClasses(DSObject) exportClasses(DSResult) +exportClasses(DSSession) import(R6) import(progress) importFrom(cli,cli_abort) diff --git a/R/DSConnection.R b/R/DSConnection.R index 35c557d..dca4af8 100644 --- a/R/DSConnection.R +++ b/R/DSConnection.R @@ -29,7 +29,6 @@ setClass("DSConnection", representation(name = "character"), contains = c("DSObj #' accessible through this connection. #' #' @param conn An object that inherits from \code{\link{DSConnection-class}}. -#' #' @return A character vector of table names. #' #' @family DSConnection generics @@ -53,6 +52,7 @@ setGeneric("dsListTables", #' #' @param conn An object that inherits from \code{\link{DSConnection-class}}. #' @param table the table fully qualified name +#' @return A logical indicating if the table exists. #' #' @family DSConnection generics #' @examples @@ -73,6 +73,7 @@ setGeneric("dsHasTable", #' accessible through this connection. #' #' @param conn An object that inherits from \code{\link{DSConnection-class}}. +#' @return A character vector of resource names. #' #' @family DSConnection generics #' @examples @@ -94,6 +95,7 @@ setGeneric("dsListResources", #' #' @param conn An object that inherits from \code{\link{DSConnection-class}}. #' @param resource the resource fully qualified name +#' @return A logical indicating if the resource exists. #' #' @family DSConnection generics #' @examples @@ -108,6 +110,52 @@ setGeneric("dsHasResource", def = function(conn, resource) standardGeneric("dsHasResource"), valueClass = "logical") +#' Check remote R session exists +#' +#' Check if a remote R session exists (not necessarily running and ready to accept +#' R commands submissions). +#' +#' @param conn An object that inherits from \code{\link{DSConnection-class}}. +#' @return A logical indicating if a remote R session exists accessible through this connection. +#' +#' @family DSConnection generics +#' @examples +#' \dontrun{ +#' con <- dsConnect(DSOpal::Opal(), "server1", +#' username = "dsuser", password = "password", url = "https://opal-demo.obiba.org") +#' dsHasSession(con) +#' dsDisconnect(con) +#' } +#' @export +setGeneric("dsHasSession", + def = function(conn) standardGeneric("dsHasSession"), + valueClass = "logical") + +#' Create a remote R session +#' +#' Create a remote R session if none exists. If a remote R session already exists, +#' it will be reused. Returns a logical indicating if a remote R session exists +#' accessible through this connection. +#' +#' @param conn An object that inherits from \code{\link{DSConnection-class}}. +#' @param async Whether the result of the call should be retrieved asynchronously. When TRUE (default) +#' the calls are parallelized over the connections, when the connection supports +#' that feature, with an extra overhead of requests. +#' @return An object of class \code{\link{DSSession-class}} representing the remote R session. +#' +#' @family DSConnection generics +#' @examples +#' \dontrun{ +#' con <- dsConnect(DSOpal::Opal(), "server1", +#' username = "dsuser", password = "password", url = "https://opal-demo.obiba.org") +#' dsSession(con, async=TRUE) +#' dsDisconnect(con) +#' } +#' @export +setGeneric("dsSession", + def = function(conn, async=TRUE) standardGeneric("dsSession"), + valueClass = "DSSession") + #' Assign a data table #' #' Assign a data table from the data repository to a symbol in the DataSHIELD R session. @@ -126,7 +174,8 @@ setGeneric("dsHasResource", #' will be the data frame row names. When specified this column can be used to perform joins between data frames. #' @param async Whether the result of the call should be retrieved asynchronously. When TRUE (default) the calls are parallelized over #' the connections, when the connection supports that feature, with an extra overhead of requests. -#' +#' @return An object of class \code{\link{DSResult-class}} representing the result of the assignment operation. +#' #' @family DSConnection generics #' @examples #' \dontrun{ @@ -150,7 +199,8 @@ setGeneric("dsAssignTable", #' @param resource Fully qualified name of a resource reference in the data repository. #' @param async Whether the result of the call should be retrieved asynchronously. When TRUE (default) the calls are parallelized over #' the connections, when the connection supports that feature, with an extra overhead of requests. -#' +#' @return An object of class \code{\link{DSResult-class}} representing the result of the assignment operation. +#' #' @family DSConnection generics #' @examples #' \dontrun{ @@ -174,7 +224,8 @@ setGeneric("dsAssignResource", #' @param expr A R expression with allowed assign functions calls. #' @param async Whether the result of the call should be retrieved asynchronously. When TRUE (default) the calls are parallelized over #' the connections, when the connection supports that feature, with an extra overhead of requests. -#' +#' @return An object of class \code{\link{DSResult-class}} representing the result of the assignment operation. +#' #' @family DSConnection generics #' @examples #' \dontrun{ @@ -197,7 +248,8 @@ setGeneric("dsAssignExpr", #' @param expr Expression to evaluate. #' @param async Whether the result of the call should be retrieved asynchronously. When TRUE (default) the calls are parallelized over #' the connections, when the connection supports that feature, with an extra overhead of requests. -#' +#' @return An object of class \code{\link{DSResult-class}} representing the result of the aggregation operation. +#' #' @family DSConnection generics #' @examples #' \dontrun{ @@ -217,6 +269,7 @@ setGeneric("dsAggregate", #' After assignments have been performed, some symbols live in the DataSHIELD R session on the server side. #' #' @param conn An object that inherits from \code{\link{DSConnection-class}}. +#' @return A character vector of symbol names. #' #' @family DSConnection generics #' @examples @@ -257,8 +310,8 @@ setGeneric("dsRmSymbol", #' Get the list of DataSHIELD profiles that have been configured on the remote data repository. #' #' @param conn An object that inherits from \code{\link{DSConnection-class}}. -#' -#' @return A list containing the "available" character vector of profile names and the "current" profile (in case a default one was assigned). +#' @return A list containing the "available" character vector of profile names and +#' the "current" profile (in case a default one was assigned). #' #' @family DSConnection generics #' @examples @@ -279,7 +332,6 @@ setGeneric("dsListProfiles", #' #' @param conn An object that inherits from \code{\link{DSConnection-class}}. #' @param type Type of the method: "aggregate" (default) or "assign". -#' #' @return A data.frame with columns: name, type ('aggregate' or 'assign'), class ('function' or 'script'), value, package, version. #' #' @family DSConnection generics @@ -300,7 +352,6 @@ setGeneric("dsListMethods", #' Get the list of DataSHIELD packages with their version, that have been configured on the remote data repository. #' #' @param conn An object that inherits from \code{\link{DSConnection-class}}. -#' #' @return A data.frame with columns: name, version. #' #' @family DSConnection generics @@ -322,7 +373,6 @@ setGeneric("dsListPackages", #' Get the list of DataSHIELD workspaces, that have been saved on the remote data repository. #' #' @param conn An object that inherits from \code{\link{DSConnection-class}}. -#' #' @return A data.frame with columns: name, lastAccessDate, size. #' #' @family DSConnection generics @@ -407,10 +457,11 @@ setGeneric("dsRmWorkspace", #' When a \code{\link{DSResult-class}} object is returned on aggregation or assignment operation, #' the raw result can be accessed asynchronously, allowing parallelization of DataSHIELD calls #' over multpile servers. The returned named list of logicals will specify if asynchronicity is supported for: -#' aggregation operation ('aggregate'), table assignment operation ('assignTable'), +#' session operation ('session'), aggregation operation ('aggregate'), table assignment operation ('assignTable'), #' resource assignment operation ('assignResource') and expression assignment operation ('assignExpr'). #' #' @param conn An object that inherits from \code{\link{DSConnection-class}}. +#' @return A named list of logicals indicating if asynchronicity is supported for session, aggregation and assignment operations. #' #' @family DSConnection generics #' @examples diff --git a/R/DSSession.R b/R/DSSession.R new file mode 100644 index 0000000..978f541 --- /dev/null +++ b/R/DSSession.R @@ -0,0 +1,68 @@ +#' DSSession class +#' +#' This virtual class describes the state of the R session. +#' +#' The default show method displays a summary of the R session state using other +#' DS generics. +#' +#' @name DSSession-class +#' @docType class +#' @family DS classes +#' @family DSSession generics +#' @export +#' @include DSObject.R +setClass("DSSession", contains = c("DSObject", "VIRTUAL")) + +#' Get whether the remote R session is up and running +#' +#' Get whether the remote R session is up and running, ready to accept R commands. +#' The primary use of this function is to know whether the session is ready after it has been +#' created in an asynchronous way. +#' +#' @param session An object inheriting from \code{\link{DSSession-class}}. +#' @return A logical +#' +#' @family DSSession generics +#' @examples +#' \dontrun{ +#' con <- dsConnect(DSOpal::Opal(), "server1", +#' username = "dsuser", password = "password", url = "https://opal-demo.obiba.org") +#' session <- dsSession(con, async = TRUE) +#' ready <- dsIsReady(session) +#' while (!ready) { +#' Sys.sleep(1) +#' ready <- dsIsReady(session) +#' cat(".") +#' } +#' dsDisconnect(con) +#' } +#' @export +setGeneric("dsIsReady", + def = function(session) standardGeneric("dsIsReady")) + +#' Get the state of the remote R session +#' +#' Get a human-readable message that informs about the state of the remote R session. +#' The primary use of this function is to inform the user about the session state process +#' after it has been created in an asynchronous way. +#' +#' @param session An object inheriting from \code{\link{DSSession-class}}. +#' @return A character string +#' +#' @family DSSession generics +#' @examples +#' \dontrun{ +#' con <- dsConnect(DSOpal::Opal(), "server1", +#' username = "dsuser", password = "password", url = "https://opal-demo.obiba.org") +#' session <- dsSession(con, async = TRUE) +#' ready <- dsIsReady(session) +#' while (!ready) { +#' Sys.sleep(1) +#' ready <- dsIsReady(session) +#' cat(dsStateMessage(session), "\n") +#' } +#' dsDisconnect(con) +#' } +#' @export +setGeneric("dsStateMessage", + def = function(session) standardGeneric("dsStateMessage")) diff --git a/R/datashield.aggregate.R b/R/datashield.aggregate.R index 490c326..23cd068 100644 --- a/R/datashield.aggregate.R +++ b/R/datashield.aggregate.R @@ -40,6 +40,7 @@ #' #' @export datashield.aggregate <- function(conns, expr, async=TRUE, success=NULL, error=NULL, errors.print = getOption("datashield.errors.print", FALSE)) { + datashield.sessions(conns) .clearLastErrors() rval <- NULL diff --git a/R/datashield.assign.R b/R/datashield.assign.R index 69265be..4ddb7bd 100644 --- a/R/datashield.assign.R +++ b/R/datashield.assign.R @@ -114,6 +114,7 @@ datashield.assign <- function(conns, symbol, value, variables=NULL, missings=FAL #' } #' @export datashield.assign.table <- function(conns, symbol, table, variables=NULL, missings=FALSE, identifiers=NULL, id.name=NULL, async=TRUE, success=NULL, error=NULL, errors.print = getOption("datashield.errors.print", FALSE)) { + datashield.sessions(conns) .clearLastErrors() if (is.null(table) || length(table) == 0) { stop("Not a valid table name", call.=FALSE) @@ -269,6 +270,7 @@ datashield.assign.table <- function(conns, symbol, table, variables=NULL, missin #' } #' @export datashield.assign.resource <- function(conns, symbol, resource, async=TRUE, success=NULL, error=NULL, errors.print = getOption("datashield.errors.print", FALSE)) { + datashield.sessions(conns) .clearLastErrors() if (is.null(resource) || length(resource) == 0) { stop("Not a valid resource name", call.=FALSE) @@ -415,6 +417,7 @@ datashield.assign.resource <- function(conns, symbol, resource, async=TRUE, succ #' } #' @export datashield.assign.expr <- function(conns, symbol, expr, async=TRUE, success=NULL, error=NULL, errors.print = getOption("datashield.errors.print", FALSE)) { + datashield.sessions(conns) .clearLastErrors() # prepare expressions as a named list diff --git a/R/datashield.login.R b/R/datashield.login.R index a417e0c..c092245 100644 --- a/R/datashield.login.R +++ b/R/datashield.login.R @@ -156,10 +156,6 @@ datashield.login <- function(logins=NULL, assign=FALSE, variables=NULL, missings doConnection <- function(i) { # connection options conn.opts <- append(opts, eval(parse(text=as.character(options[[i]])))) - restoreId <- restore - if (!is.null(restore)) { - restoreId <- paste0(stdnames[i], ":", restore) - } # instanciate the DSDriver drv <- new(drivers[i]) # if the connection is HTTPS use ssl options else they are not required @@ -171,12 +167,12 @@ datashield.login <- function(logins=NULL, assign=FALSE, variables=NULL, missings cert <- userids[i] private <- pwds[i] conn.opts <- append(conn.opts, list(sslcert=cert, sslkey=private)) - conn.obj <- dsConnect(drv, name=stdnames[i], url=urls[i], opts=conn.opts, profile=profiles[i], restore=restoreId) + conn.obj <- dsConnect(drv, name=stdnames[i], url=urls[i], opts=conn.opts, profile=profiles[i]) } else { - conn.obj <- dsConnect(drv, name=stdnames[i], username=userids[i], password=pwds[i], token=tokens[i], url=urls[i], profile=profiles[i], opts=conn.opts, restore=restoreId) + conn.obj <- dsConnect(drv, name=stdnames[i], username=userids[i], password=pwds[i], token=tokens[i], url=urls[i], profile=profiles[i], opts=conn.opts) } } else { - conn.obj <- dsConnect(drv, name=stdnames[i], username=userids[i], password=pwds[i], token=tokens[i], url=urls[i], profile=profiles[i], opts=conn.opts, restore=restoreId) + conn.obj <- dsConnect(drv, name=stdnames[i], username=userids[i], password=pwds[i], token=tokens[i], url=urls[i], profile=profiles[i], opts=conn.opts) } conn.obj } @@ -227,135 +223,30 @@ datashield.login <- function(logins=NULL, assign=FALSE, variables=NULL, missings rconnections <- append(rconnections, x) } } + + # if restore is not null, restore the workspaces + if (!is.null(restore) && length(rconnections) > 0) { + datashield.workspace_restore(rconnections, restore) + } # if argument 'assign' is true assign data/resources to the data repository server(s) you logged in to. if(assign && length(rconnections) > 0) { - + #warning("Assignment of table/resources at login time is deprecated. Use datashield.assign functions instead.", call.=FALSE, immediate.=TRUE) isNotEmpty <- Vectorize(function(x) { !(is.null(x) || is.na(x) || length(x) == 0 || nchar(x) == 0) }) - - assignResources <- function() { - # Assign resource data in parallel - message("\nAssigning resource data...") - results <- list() - async <- c() - for (i in 1:length(connections)) { - if (excluded[i]) { - async <- append(async, FALSE) - } else { - async <- append(async, dsIsAsync(connections[[i]])$assignResource) - } - } - # async first - - pb <- .newProgress(total = 1 + length(connections) - length(excluded[excluded == TRUE])) - for (i in 1:length(connections)) { - if(!excluded[i] && async[i]) { - results[[i]] <- dsAssignResource(connections[[i]], symbol, resources[i]) - } - } - # not async (blocking calls) - for (i in 1:length(connections)) { - if(!excluded[i] && !async[i]) { - .tickProgress(pb, tokens = list(what = paste0("Assigning ", stdnames[i], " (", resources[i], ")"))) - results[[i]] <- dsAssignResource(connections[[i]], symbol, resources[i]) - } - } - for (i in 1:length(connections)) { - if(!excluded[i]) { - res <- results[[i]] - if (!is.null(res)) { - if (async[i]) { - .tickProgress(pb, tokens = list(what = paste0("Assigning ", stdnames[i], " (", resources[i], ")"))) - } - resInfo <- dsGetInfo(res) - if (resInfo$status == "FAILED") { - warning("Resource assignment of '", resources[i], "' failed for '", stdnames[i],"': ", resInfo$error, call.=FALSE, immediate.=TRUE) - } - } - } - } - .tickProgress(pb, tokens = list(what = "Assigned all resources")) - } - - assignTables <- function() { - if(is.null(variables)) { - # if the user does not specify variables (default behaviour) - # display a message telling the user that the whole dataset - # will be assigned since he did not specify variables - message("\n No variables have been specified. \n All the variables in the table \n (the whole dataset) will be assigned to R!") - } - - # Assign table data in parallel - message("\nAssigning table data...") - results <- list() - async <- c() - for (i in 1:length(connections)) { - if (excluded[i]) { - async <- append(async, FALSE) - } else { - async <- append(async, dsIsAsync(connections[[i]])$assignTable) - } - } - # async first - - pb <- .newProgress(total = 1 + length(connections) - length(excluded[excluded == TRUE])) - for (i in 1:length(connections)) { - if(!excluded[i] && async[i]) { - results[[i]] <- dsAssignTable(connections[[i]], symbol, tables[i], variables=variables, missings=missings, identifiers=idmappings[i], id.name=id.name) - } - } - # not async (blocking calls) - for (i in 1:length(connections)) { - if(!excluded[i] && !async[i]) { - .tickProgress(pb, tokens = list(what = paste0("Assigning ", stdnames[i], " (", tables[i], ")"))) - results[[i]] <- dsAssignTable(connections[[i]], symbol, tables[i], variables=variables, missings=missings, identifiers=idmappings[i], id.name=id.name) - } - } - for (i in 1:length(connections)) { - if(!excluded[i]) { - res <- results[[i]] - if (!is.null(res)) { - if (async[i]) { - .tickProgress(pb, tokens = list(what = paste0("Assigning ", stdnames[i], " (", tables[i], ")"))) - } - resInfo <- dsGetInfo(res) - if (resInfo$status == "FAILED") { - warning("Data assignment of '", tables[i], "' failed for '", stdnames[i],"': ", resInfo$error, call.=FALSE, immediate.=TRUE) - } - } - } - } - .tickProgress(pb, tokens = list(what = "Assigned all tables")) - - # Get column names in parallel - # Ensure the colnames aggregation is available - aggs <- datashield.method_status(rconnections, type="aggregate") - hasColnames <- aggs[aggs$name == "colnames",] - if (nrow(hasColnames)>0) { - message("\nVariables assigned:") - lapply(names(rconnections), function(n) { - if (hasColnames[[n]]) { - varnames <- dsFetch(dsAggregate(rconnections[[n]], paste0('colnames(', symbol,')'), async = FALSE)) - if(length(varnames[[1]]) > 0) { - message(n, " -- ", paste(unlist(varnames), collapse=", ")) - } else { - message(n, " -- No variables assigned. Please check login details for this study and verify that the variables are available!") - } - } else { - message(n, " -- ? (colnames() aggregation method not available)") - } - }) - } - } - if (all(isNotEmpty(resources))) { - assignResources() + tryCatch({ + datashield.assign.resource(rconnections, symbol = symbol, resource = logins) + }, error = function(e) { + warning("Resource assignment failed", call.=FALSE, immediate.=TRUE) + }) } - if (all(isNotEmpty(tables))) { - assignTables() + tryCatch({ + datashield.assign.table(rconnections, symbol = symbol, table = logins, variables = variables, missings = missings, id.name = id.name) + }, error = function(e) { + warning("Resource assignment failed", call.=FALSE, immediate.=TRUE) + }) } - } .clearCache() diff --git a/R/datashield.sessions.R b/R/datashield.sessions.R new file mode 100644 index 0000000..bffd2d8 --- /dev/null +++ b/R/datashield.sessions.R @@ -0,0 +1,133 @@ +#' R/DataSHIELD remote sessions +#' +#' Ensure that the remote R sessions are up and running during the analysis. +#' +#' @param conns \code{\link{DSConnection-class}} object or a list of \code{\link{DSConnection-class}}s. +#' @param async Whether the remote R/DataSHIELD session should be created asynchronously. When TRUE (default) the calls are parallelized over +#' the connections, when the connection supports that feature, with an extra overhead of requests. +#' @param success Callback function that will be called each time an R session has been created from a connection. +#' The expected function signature is the connection/study name. Default is NULL (no callback). +#' @param error Callback function that will be called each time the R session creation request has failed. +#' The expected function signature is the connection/study name and the error message. Default is NULL (no callback). +#' @param errors.print Boolean, whether to print datashield errors in the console or return a message indicating that they can be retrieved using `datashield.errors`. +#' +#' @examples +#'\dontrun{ +#' # call sessions function on server side asynchronously +#' # i.e. each study connection will create a remote R session in parallel +#' datashield.sessions(conns) +#' +#' # call sessions function with callback functions +#' result <- datashield.sessions(conns, +#' success = function(server) { +#' # do something with server's success +#' }, +#' error = function(server, error) { +#' # do something with server's error +#' }) +#' } +#' +#' @export +datashield.sessions <- function(conns, async=TRUE, success=NULL, error=NULL, errors.print = getOption("datashield.errors.print", FALSE)) { + .clearLastErrors() + + if (is.list(conns)) { + # filter conns supporting session API and not having connection + fconns <- Filter(function(conn) { !is.null(dsIsAsync(conn)$session) && !dsHasSession(conn) }, conns) + if (length(fconns) == 0) { + return(invisible(NULL)) + } + + sessions <- list() + asyncs <- lapply(fconns, function(conn) { ifelse(async, dsIsAsync(conn)$session, FALSE) }) + pb <- .newProgress(total = 1 + length(fconns)) + # async first + for (n in names(fconns)) { + if(asyncs[[n]]) { + tryCatch({ + sessions[[n]] <- dsSession(fconns[[n]], async=async) + }, error = function(e) { + .appendError(n, conditionMessage(e)) + if (.is.callback(error)) { + error(n, conditionMessage(e)) + } + }) + } + } + # not async (blocking calls) + for (n in names(fconns)) { + if(!asyncs[[n]]) { + tryCatch({ + .tickProgress(pb, tokens = list(what = paste0("Session ", fconns[[n]]@name))) + sessions[[n]] <- dsSession(fconns[[n]], async=FALSE) + }, error = function(e) { + .appendError(n, conditionMessage(e)) + if (.is.callback(error)) { + error(n, conditionMessage(e)) + } + }) + } + } + # polling + completed <- replicate(length(fconns), FALSE) + names(completed) <- names(fconns) + checks <- 1 + while (!all(completed)) { + messages <- c() + for (n in names(fconns)) { + if (!completed[[n]]) { + if (!.hasLastErrors(n)) { + tryCatch({ + msg <- paste0(fconns[[n]]@name, ": ", dsStateMessage(sessions[[n]])) + messages <- append(messages, msg) + if(asyncs[[n]]) { + completed[[n]] <- dsIsReady(sessions[[n]]) + if (completed[[n]]) { + .tickProgress(pb, tokens = list(what = msg)) + } + } else { + completed[[n]] <- TRUE + } + if (completed[[n]] && .is.callback(success)) { + success(n) + } + }, error = function(e) { + .appendError(n, conditionMessage(e)) + completed[[n]] <- TRUE + if (.is.callback(error)) { + error(n, conditionMessage(e)) + } + }) + } else { + completed[[n]] <- TRUE + } + } else { + # heart beat request + dsKeepAlive(fconns[[n]]) + } + } + if (!all(completed)) { + .updateProgress(pb, step = length(subset(completed, completed == TRUE)), total = length(fconns), tokens = list(what = paste(messages, collapse = ", "))) + Sys.sleep(.getSleepTime(checks)) + checks <- checks + 1 + } + } + ignore <- .tickProgress(pb, tokens = list(what = paste0("All R sessions ready"))) + } else if (!is.null(dsIsAsync(conns)$session)) { + tryCatch({ + if (!dsHasSession(conns)) { + dsSession(conns, async=FALSE) + } + if (.is.callback(success)) { + success(conns@name) + } + }, error = function(e) { + .appendError(conns@name, conditionMessage(e)) + if (.is.callback(error)) { + error(conns@name, conditionMessage(e)) + } + }) + } + .handle_errors(errors.print) + invisible(NULL) +} diff --git a/R/datashield.symbol.R b/R/datashield.symbol.R index 3915a29..e5017f8 100644 --- a/R/datashield.symbol.R +++ b/R/datashield.symbol.R @@ -6,6 +6,7 @@ #' #' @export datashield.symbols <- function(conns) { + datashield.sessions(conns) if (is.list(conns)) { lapply(conns, FUN=datashield.symbols) } else { diff --git a/R/datashield.workspace.R b/R/datashield.workspace.R index f745f9f..a5ea80a 100644 --- a/R/datashield.workspace.R +++ b/R/datashield.workspace.R @@ -42,6 +42,7 @@ datashield.workspaces <- function(conns) { #' @param ws The workspace name #' @export datashield.workspace_save <- function(conns, ws) { + datashield.sessions(conns) if (is.list(conns)) { ignore <- lapply(conns, function(c) datashield.workspace_save(c, ws)) } else { @@ -60,6 +61,7 @@ datashield.workspace_save <- function(conns, ws) { #' @param ws The workspace name #' @export datashield.workspace_restore <- function(conns, ws) { + datashield.sessions(conns) if (is.list(conns)) { ignore <- lapply(conns, function(c) datashield.workspace_restore(c, ws)) } else { diff --git a/man/DSConnection-class.Rd b/man/DSConnection-class.Rd index ea6cfe8..4b8853d 100644 --- a/man/DSConnection-class.Rd +++ b/man/DSConnection-class.Rd @@ -27,7 +27,8 @@ dsDisconnect(con) Other DS classes: \code{\link{DSDriver-class}}, \code{\link{DSObject-class}}, -\code{\link{DSResult-class}} +\code{\link{DSResult-class}}, +\code{\link{DSSession-class}} Other DSConnection generics: \code{\link{dsAggregate}()}, @@ -37,6 +38,7 @@ Other DSConnection generics: \code{\link{dsDisconnect}()}, \code{\link{dsGetInfo}()}, \code{\link{dsHasResource}()}, +\code{\link{dsHasSession}()}, \code{\link{dsHasTable}()}, \code{\link{dsIsAsync}()}, \code{\link{dsKeepAlive}()}, @@ -50,7 +52,8 @@ Other DSConnection generics: \code{\link{dsRestoreWorkspace}()}, \code{\link{dsRmSymbol}()}, \code{\link{dsRmWorkspace}()}, -\code{\link{dsSaveWorkspace}()} +\code{\link{dsSaveWorkspace}()}, +\code{\link{dsSession}()} } \concept{DS classes} \concept{DSConnection generics} diff --git a/man/DSDriver-class.Rd b/man/DSDriver-class.Rd index cc1793b..e39dc44 100644 --- a/man/DSDriver-class.Rd +++ b/man/DSDriver-class.Rd @@ -13,7 +13,8 @@ connections. Other DS classes: \code{\link{DSConnection-class}}, \code{\link{DSObject-class}}, -\code{\link{DSResult-class}} +\code{\link{DSResult-class}}, +\code{\link{DSSession-class}} Other DSDriver generics: \code{\link{dsConnect}()}, diff --git a/man/DSObject-class.Rd b/man/DSObject-class.Rd index 754bb2f..3aef8e0 100644 --- a/man/DSObject-class.Rd +++ b/man/DSObject-class.Rd @@ -53,6 +53,7 @@ dsDisconnect(con) Other DS classes: \code{\link{DSConnection-class}}, \code{\link{DSDriver-class}}, -\code{\link{DSResult-class}} +\code{\link{DSResult-class}}, +\code{\link{DSSession-class}} } \concept{DS classes} diff --git a/man/DSResult-class.Rd b/man/DSResult-class.Rd index 8ef40a8..6e39395 100644 --- a/man/DSResult-class.Rd +++ b/man/DSResult-class.Rd @@ -21,7 +21,8 @@ DS generics. Other DS classes: \code{\link{DSConnection-class}}, \code{\link{DSDriver-class}}, -\code{\link{DSObject-class}} +\code{\link{DSObject-class}}, +\code{\link{DSSession-class}} Other DSResult generics: \code{\link{dsFetch}()}, diff --git a/man/DSSession-class.Rd b/man/DSSession-class.Rd new file mode 100644 index 0000000..4681315 --- /dev/null +++ b/man/DSSession-class.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/DSSession.R +\docType{class} +\name{DSSession-class} +\alias{DSSession-class} +\title{DSSession class} +\description{ +This virtual class describes the state of the R session. +} +\details{ +The default show method displays a summary of the R session state using other +DS generics. +} +\seealso{ +Other DS classes: +\code{\link{DSConnection-class}}, +\code{\link{DSDriver-class}}, +\code{\link{DSObject-class}}, +\code{\link{DSResult-class}} + +Other DSSession generics: +\code{\link{dsIsReady}()}, +\code{\link{dsStateMessage}()} +} +\concept{DS classes} +\concept{DSSession generics} diff --git a/man/datashield.sessions.Rd b/man/datashield.sessions.Rd new file mode 100644 index 0000000..d509496 --- /dev/null +++ b/man/datashield.sessions.Rd @@ -0,0 +1,48 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/datashield.sessions.R +\name{datashield.sessions} +\alias{datashield.sessions} +\title{R/DataSHIELD remote sessions} +\usage{ +datashield.sessions( + conns, + async = TRUE, + success = NULL, + error = NULL, + errors.print = getOption("datashield.errors.print", FALSE) +) +} +\arguments{ +\item{conns}{\code{\link{DSConnection-class}} object or a list of \code{\link{DSConnection-class}}s.} + +\item{async}{Whether the remote R/DataSHIELD session should be created asynchronously. When TRUE (default) the calls are parallelized over +the connections, when the connection supports that feature, with an extra overhead of requests.} + +\item{success}{Callback function that will be called each time an R session has been created from a connection. +The expected function signature is the connection/study name. Default is NULL (no callback).} + +\item{error}{Callback function that will be called each time the R session creation request has failed. +The expected function signature is the connection/study name and the error message. Default is NULL (no callback).} + +\item{errors.print}{Boolean, whether to print datashield errors in the console or return a message indicating that they can be retrieved using `datashield.errors`.} +} +\description{ +Ensure that the remote R sessions are up and running during the analysis. +} +\examples{ +\dontrun{ +# call sessions function on server side asynchronously +# i.e. each study connection will create a remote R session in parallel +datashield.sessions(conns) + +# call sessions function with callback functions +result <- datashield.sessions(conns, + success = function(server) { + # do something with server's success + }, + error = function(server, error) { + # do something with server's error + }) +} + +} diff --git a/man/dsAggregate.Rd b/man/dsAggregate.Rd index 4da9640..6fbfd17 100644 --- a/man/dsAggregate.Rd +++ b/man/dsAggregate.Rd @@ -14,6 +14,9 @@ dsAggregate(conn, expr, async = TRUE) \item{async}{Whether the result of the call should be retrieved asynchronously. When TRUE (default) the calls are parallelized over the connections, when the connection supports that feature, with an extra overhead of requests.} } +\value{ +An object of class \code{\link{DSResult-class}} representing the result of the aggregation operation. +} \description{ Aggregate some data from the DataSHIELD R session using a valid R expression. The aggregation expression must satisfy the data repository's DataSHIELD configuration. @@ -36,6 +39,7 @@ Other DSConnection generics: \code{\link{dsDisconnect}()}, \code{\link{dsGetInfo}()}, \code{\link{dsHasResource}()}, +\code{\link{dsHasSession}()}, \code{\link{dsHasTable}()}, \code{\link{dsIsAsync}()}, \code{\link{dsKeepAlive}()}, @@ -49,6 +53,7 @@ Other DSConnection generics: \code{\link{dsRestoreWorkspace}()}, \code{\link{dsRmSymbol}()}, \code{\link{dsRmWorkspace}()}, -\code{\link{dsSaveWorkspace}()} +\code{\link{dsSaveWorkspace}()}, +\code{\link{dsSession}()} } \concept{DSConnection generics} diff --git a/man/dsAssignExpr.Rd b/man/dsAssignExpr.Rd index a592472..d3d8a9c 100644 --- a/man/dsAssignExpr.Rd +++ b/man/dsAssignExpr.Rd @@ -16,6 +16,9 @@ dsAssignExpr(conn, symbol, expr, async = TRUE) \item{async}{Whether the result of the call should be retrieved asynchronously. When TRUE (default) the calls are parallelized over the connections, when the connection supports that feature, with an extra overhead of requests.} } +\value{ +An object of class \code{\link{DSResult-class}} representing the result of the assignment operation. +} \description{ Assign the result of the evaluation of an expression to a symbol the DataSHIELD R session The assignment expression must satisfy the data repository's DataSHIELD configuration. @@ -37,6 +40,7 @@ Other DSConnection generics: \code{\link{dsDisconnect}()}, \code{\link{dsGetInfo}()}, \code{\link{dsHasResource}()}, +\code{\link{dsHasSession}()}, \code{\link{dsHasTable}()}, \code{\link{dsIsAsync}()}, \code{\link{dsKeepAlive}()}, @@ -50,6 +54,7 @@ Other DSConnection generics: \code{\link{dsRestoreWorkspace}()}, \code{\link{dsRmSymbol}()}, \code{\link{dsRmWorkspace}()}, -\code{\link{dsSaveWorkspace}()} +\code{\link{dsSaveWorkspace}()}, +\code{\link{dsSession}()} } \concept{DSConnection generics} diff --git a/man/dsAssignResource.Rd b/man/dsAssignResource.Rd index c66b817..6bd899a 100644 --- a/man/dsAssignResource.Rd +++ b/man/dsAssignResource.Rd @@ -16,6 +16,9 @@ dsAssignResource(conn, symbol, resource, async = TRUE) \item{async}{Whether the result of the call should be retrieved asynchronously. When TRUE (default) the calls are parallelized over the connections, when the connection supports that feature, with an extra overhead of requests.} } +\value{ +An object of class \code{\link{DSResult-class}} representing the result of the assignment operation. +} \description{ Assign a resource object of class 'ResourceClient' from the data repository to a symbol in the DataSHIELD R session. The resource reference to be assigned must exist (i.e. proper permissions apply) for the DataSHIELD user. @@ -37,6 +40,7 @@ Other DSConnection generics: \code{\link{dsDisconnect}()}, \code{\link{dsGetInfo}()}, \code{\link{dsHasResource}()}, +\code{\link{dsHasSession}()}, \code{\link{dsHasTable}()}, \code{\link{dsIsAsync}()}, \code{\link{dsKeepAlive}()}, @@ -50,6 +54,7 @@ Other DSConnection generics: \code{\link{dsRestoreWorkspace}()}, \code{\link{dsRmSymbol}()}, \code{\link{dsRmWorkspace}()}, -\code{\link{dsSaveWorkspace}()} +\code{\link{dsSaveWorkspace}()}, +\code{\link{dsSession}()} } \concept{DSConnection generics} diff --git a/man/dsAssignTable.Rd b/man/dsAssignTable.Rd index ec07e68..2014f6f 100644 --- a/man/dsAssignTable.Rd +++ b/man/dsAssignTable.Rd @@ -37,6 +37,9 @@ will be the data frame row names. When specified this column can be used to perf \item{async}{Whether the result of the call should be retrieved asynchronously. When TRUE (default) the calls are parallelized over the connections, when the connection supports that feature, with an extra overhead of requests.} } +\value{ +An object of class \code{\link{DSResult-class}} representing the result of the assignment operation. +} \description{ Assign a data table from the data repository to a symbol in the DataSHIELD R session. The table to be assigned must exist (i.e. proper permissions apply) for the DataSHIELD user. @@ -58,6 +61,7 @@ Other DSConnection generics: \code{\link{dsDisconnect}()}, \code{\link{dsGetInfo}()}, \code{\link{dsHasResource}()}, +\code{\link{dsHasSession}()}, \code{\link{dsHasTable}()}, \code{\link{dsIsAsync}()}, \code{\link{dsKeepAlive}()}, @@ -71,6 +75,7 @@ Other DSConnection generics: \code{\link{dsRestoreWorkspace}()}, \code{\link{dsRmSymbol}()}, \code{\link{dsRmWorkspace}()}, -\code{\link{dsSaveWorkspace}()} +\code{\link{dsSaveWorkspace}()}, +\code{\link{dsSession}()} } \concept{DSConnection generics} diff --git a/man/dsDisconnect.Rd b/man/dsDisconnect.Rd index 2916ad8..42ef4d1 100644 --- a/man/dsDisconnect.Rd +++ b/man/dsDisconnect.Rd @@ -31,6 +31,7 @@ Other DSConnection generics: \code{\link{dsAssignTable}()}, \code{\link{dsGetInfo}()}, \code{\link{dsHasResource}()}, +\code{\link{dsHasSession}()}, \code{\link{dsHasTable}()}, \code{\link{dsIsAsync}()}, \code{\link{dsKeepAlive}()}, @@ -44,6 +45,7 @@ Other DSConnection generics: \code{\link{dsRestoreWorkspace}()}, \code{\link{dsRmSymbol}()}, \code{\link{dsRmWorkspace}()}, -\code{\link{dsSaveWorkspace}()} +\code{\link{dsSaveWorkspace}()}, +\code{\link{dsSession}()} } \concept{DSConnection generics} diff --git a/man/dsGetInfo.Rd b/man/dsGetInfo.Rd index c1b970d..4fcb14a 100644 --- a/man/dsGetInfo.Rd +++ b/man/dsGetInfo.Rd @@ -50,6 +50,7 @@ Other DSConnection generics: \code{\link{dsAssignTable}()}, \code{\link{dsDisconnect}()}, \code{\link{dsHasResource}()}, +\code{\link{dsHasSession}()}, \code{\link{dsHasTable}()}, \code{\link{dsIsAsync}()}, \code{\link{dsKeepAlive}()}, @@ -63,7 +64,8 @@ Other DSConnection generics: \code{\link{dsRestoreWorkspace}()}, \code{\link{dsRmSymbol}()}, \code{\link{dsRmWorkspace}()}, -\code{\link{dsSaveWorkspace}()} +\code{\link{dsSaveWorkspace}()}, +\code{\link{dsSession}()} Other DSResult generics: \code{\link{DSResult-class}}, diff --git a/man/dsHasResource.Rd b/man/dsHasResource.Rd index 28acf43..c48f39d 100644 --- a/man/dsHasResource.Rd +++ b/man/dsHasResource.Rd @@ -11,6 +11,9 @@ dsHasResource(conn, resource) \item{resource}{the resource fully qualified name} } +\value{ +A logical indicating if the resource exists. +} \description{ Check if a remote resource reference exists in the data repository. Returns a logical indicating the existence of a remote resource accessible through this connection. @@ -32,6 +35,7 @@ Other DSConnection generics: \code{\link{dsAssignTable}()}, \code{\link{dsDisconnect}()}, \code{\link{dsGetInfo}()}, +\code{\link{dsHasSession}()}, \code{\link{dsHasTable}()}, \code{\link{dsIsAsync}()}, \code{\link{dsKeepAlive}()}, @@ -45,6 +49,7 @@ Other DSConnection generics: \code{\link{dsRestoreWorkspace}()}, \code{\link{dsRmSymbol}()}, \code{\link{dsRmWorkspace}()}, -\code{\link{dsSaveWorkspace}()} +\code{\link{dsSaveWorkspace}()}, +\code{\link{dsSession}()} } \concept{DSConnection generics} diff --git a/man/dsHasSession.Rd b/man/dsHasSession.Rd new file mode 100644 index 0000000..ee24135 --- /dev/null +++ b/man/dsHasSession.Rd @@ -0,0 +1,53 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/DSConnection.R +\name{dsHasSession} +\alias{dsHasSession} +\title{Check remote R session exists} +\usage{ +dsHasSession(conn) +} +\arguments{ +\item{conn}{An object that inherits from \code{\link{DSConnection-class}}.} +} +\value{ +A logical indicating if a remote R session exists accessible through this connection. +} +\description{ +Check if a remote R session exists (not necessarily running and ready to accept +R commands submissions). +} +\examples{ +\dontrun{ +con <- dsConnect(DSOpal::Opal(), "server1", + username = "dsuser", password = "password", url = "https://opal-demo.obiba.org") +dsHasSession(con) +dsDisconnect(con) +} +} +\seealso{ +Other DSConnection generics: +\code{\link{DSConnection-class}}, +\code{\link{dsAggregate}()}, +\code{\link{dsAssignExpr}()}, +\code{\link{dsAssignResource}()}, +\code{\link{dsAssignTable}()}, +\code{\link{dsDisconnect}()}, +\code{\link{dsGetInfo}()}, +\code{\link{dsHasResource}()}, +\code{\link{dsHasTable}()}, +\code{\link{dsIsAsync}()}, +\code{\link{dsKeepAlive}()}, +\code{\link{dsListMethods}()}, +\code{\link{dsListPackages}()}, +\code{\link{dsListProfiles}()}, +\code{\link{dsListResources}()}, +\code{\link{dsListSymbols}()}, +\code{\link{dsListTables}()}, +\code{\link{dsListWorkspaces}()}, +\code{\link{dsRestoreWorkspace}()}, +\code{\link{dsRmSymbol}()}, +\code{\link{dsRmWorkspace}()}, +\code{\link{dsSaveWorkspace}()}, +\code{\link{dsSession}()} +} +\concept{DSConnection generics} diff --git a/man/dsHasTable.Rd b/man/dsHasTable.Rd index 7944d90..cc2f89a 100644 --- a/man/dsHasTable.Rd +++ b/man/dsHasTable.Rd @@ -11,6 +11,9 @@ dsHasTable(conn, table) \item{table}{the table fully qualified name} } +\value{ +A logical indicating if the table exists. +} \description{ Check if a remote table exists in the data repository. Returns a logical indicating the existence of a remote table accessible through this connection. @@ -33,6 +36,7 @@ Other DSConnection generics: \code{\link{dsDisconnect}()}, \code{\link{dsGetInfo}()}, \code{\link{dsHasResource}()}, +\code{\link{dsHasSession}()}, \code{\link{dsIsAsync}()}, \code{\link{dsKeepAlive}()}, \code{\link{dsListMethods}()}, @@ -45,6 +49,7 @@ Other DSConnection generics: \code{\link{dsRestoreWorkspace}()}, \code{\link{dsRmSymbol}()}, \code{\link{dsRmWorkspace}()}, -\code{\link{dsSaveWorkspace}()} +\code{\link{dsSaveWorkspace}()}, +\code{\link{dsSession}()} } \concept{DSConnection generics} diff --git a/man/dsIsAsync.Rd b/man/dsIsAsync.Rd index 12c5a2c..5bf9840 100644 --- a/man/dsIsAsync.Rd +++ b/man/dsIsAsync.Rd @@ -9,11 +9,14 @@ dsIsAsync(conn) \arguments{ \item{conn}{An object that inherits from \code{\link{DSConnection-class}}.} } +\value{ +A named list of logicals indicating if asynchronicity is supported for session, aggregation and assignment operations. +} \description{ When a \code{\link{DSResult-class}} object is returned on aggregation or assignment operation, the raw result can be accessed asynchronously, allowing parallelization of DataSHIELD calls over multpile servers. The returned named list of logicals will specify if asynchronicity is supported for: -aggregation operation ('aggregate'), table assignment operation ('assignTable'), +session operation ('session'), aggregation operation ('aggregate'), table assignment operation ('assignTable'), resource assignment operation ('assignResource') and expression assignment operation ('assignExpr'). } \examples{ @@ -34,6 +37,7 @@ Other DSConnection generics: \code{\link{dsDisconnect}()}, \code{\link{dsGetInfo}()}, \code{\link{dsHasResource}()}, +\code{\link{dsHasSession}()}, \code{\link{dsHasTable}()}, \code{\link{dsKeepAlive}()}, \code{\link{dsListMethods}()}, @@ -46,6 +50,7 @@ Other DSConnection generics: \code{\link{dsRestoreWorkspace}()}, \code{\link{dsRmSymbol}()}, \code{\link{dsRmWorkspace}()}, -\code{\link{dsSaveWorkspace}()} +\code{\link{dsSaveWorkspace}()}, +\code{\link{dsSession}()} } \concept{DSConnection generics} diff --git a/man/dsIsReady.Rd b/man/dsIsReady.Rd new file mode 100644 index 0000000..69c35ee --- /dev/null +++ b/man/dsIsReady.Rd @@ -0,0 +1,39 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/DSSession.R +\name{dsIsReady} +\alias{dsIsReady} +\title{Get whether the remote R session is up and running} +\usage{ +dsIsReady(session) +} +\arguments{ +\item{session}{An object inheriting from \code{\link{DSSession-class}}.} +} +\value{ +A logical +} +\description{ +Get whether the remote R session is up and running, ready to accept R commands. +The primary use of this function is to know whether the session is ready after it has been +created in an asynchronous way. +} +\examples{ +\dontrun{ +con <- dsConnect(DSOpal::Opal(), "server1", + username = "dsuser", password = "password", url = "https://opal-demo.obiba.org") +session <- dsSession(con, async = TRUE) +ready <- dsIsReady(session) +while (!ready) { + Sys.sleep(1) + ready <- dsIsReady(session) + cat(".") +} +dsDisconnect(con) +} +} +\seealso{ +Other DSSession generics: +\code{\link{DSSession-class}}, +\code{\link{dsStateMessage}()} +} +\concept{DSSession generics} diff --git a/man/dsKeepAlive.Rd b/man/dsKeepAlive.Rd index 983a200..e213b03 100644 --- a/man/dsKeepAlive.Rd +++ b/man/dsKeepAlive.Rd @@ -32,6 +32,7 @@ Other DSConnection generics: \code{\link{dsDisconnect}()}, \code{\link{dsGetInfo}()}, \code{\link{dsHasResource}()}, +\code{\link{dsHasSession}()}, \code{\link{dsHasTable}()}, \code{\link{dsIsAsync}()}, \code{\link{dsListMethods}()}, @@ -44,6 +45,7 @@ Other DSConnection generics: \code{\link{dsRestoreWorkspace}()}, \code{\link{dsRmSymbol}()}, \code{\link{dsRmWorkspace}()}, -\code{\link{dsSaveWorkspace}()} +\code{\link{dsSaveWorkspace}()}, +\code{\link{dsSession}()} } \concept{DSConnection generics} diff --git a/man/dsListMethods.Rd b/man/dsListMethods.Rd index c646adf..d42b704 100644 --- a/man/dsListMethods.Rd +++ b/man/dsListMethods.Rd @@ -35,6 +35,7 @@ Other DSConnection generics: \code{\link{dsDisconnect}()}, \code{\link{dsGetInfo}()}, \code{\link{dsHasResource}()}, +\code{\link{dsHasSession}()}, \code{\link{dsHasTable}()}, \code{\link{dsIsAsync}()}, \code{\link{dsKeepAlive}()}, @@ -47,6 +48,7 @@ Other DSConnection generics: \code{\link{dsRestoreWorkspace}()}, \code{\link{dsRmSymbol}()}, \code{\link{dsRmWorkspace}()}, -\code{\link{dsSaveWorkspace}()} +\code{\link{dsSaveWorkspace}()}, +\code{\link{dsSession}()} } \concept{DSConnection generics} diff --git a/man/dsListPackages.Rd b/man/dsListPackages.Rd index a0dc12b..8e938f9 100644 --- a/man/dsListPackages.Rd +++ b/man/dsListPackages.Rd @@ -33,6 +33,7 @@ Other DSConnection generics: \code{\link{dsDisconnect}()}, \code{\link{dsGetInfo}()}, \code{\link{dsHasResource}()}, +\code{\link{dsHasSession}()}, \code{\link{dsHasTable}()}, \code{\link{dsIsAsync}()}, \code{\link{dsKeepAlive}()}, @@ -45,6 +46,7 @@ Other DSConnection generics: \code{\link{dsRestoreWorkspace}()}, \code{\link{dsRmSymbol}()}, \code{\link{dsRmWorkspace}()}, -\code{\link{dsSaveWorkspace}()} +\code{\link{dsSaveWorkspace}()}, +\code{\link{dsSession}()} } \concept{DSConnection generics} diff --git a/man/dsListProfiles.Rd b/man/dsListProfiles.Rd index f2a015a..9dfd1be 100644 --- a/man/dsListProfiles.Rd +++ b/man/dsListProfiles.Rd @@ -10,7 +10,8 @@ dsListProfiles(conn) \item{conn}{An object that inherits from \code{\link{DSConnection-class}}.} } \value{ -A list containing the "available" character vector of profile names and the "current" profile (in case a default one was assigned). +A list containing the "available" character vector of profile names and +the "current" profile (in case a default one was assigned). } \description{ Get the list of DataSHIELD profiles that have been configured on the remote data repository. @@ -33,6 +34,7 @@ Other DSConnection generics: \code{\link{dsDisconnect}()}, \code{\link{dsGetInfo}()}, \code{\link{dsHasResource}()}, +\code{\link{dsHasSession}()}, \code{\link{dsHasTable}()}, \code{\link{dsIsAsync}()}, \code{\link{dsKeepAlive}()}, @@ -45,6 +47,7 @@ Other DSConnection generics: \code{\link{dsRestoreWorkspace}()}, \code{\link{dsRmSymbol}()}, \code{\link{dsRmWorkspace}()}, -\code{\link{dsSaveWorkspace}()} +\code{\link{dsSaveWorkspace}()}, +\code{\link{dsSession}()} } \concept{DSConnection generics} diff --git a/man/dsListResources.Rd b/man/dsListResources.Rd index 44eb9cb..65ebbe9 100644 --- a/man/dsListResources.Rd +++ b/man/dsListResources.Rd @@ -9,6 +9,9 @@ dsListResources(conn) \arguments{ \item{conn}{An object that inherits from \code{\link{DSConnection-class}}.} } +\value{ +A character vector of resource names. +} \description{ List remote resources from the data repository. Returns the unquoted names of remote resources accessible through this connection. @@ -31,6 +34,7 @@ Other DSConnection generics: \code{\link{dsDisconnect}()}, \code{\link{dsGetInfo}()}, \code{\link{dsHasResource}()}, +\code{\link{dsHasSession}()}, \code{\link{dsHasTable}()}, \code{\link{dsIsAsync}()}, \code{\link{dsKeepAlive}()}, @@ -43,6 +47,7 @@ Other DSConnection generics: \code{\link{dsRestoreWorkspace}()}, \code{\link{dsRmSymbol}()}, \code{\link{dsRmWorkspace}()}, -\code{\link{dsSaveWorkspace}()} +\code{\link{dsSaveWorkspace}()}, +\code{\link{dsSession}()} } \concept{DSConnection generics} diff --git a/man/dsListSymbols.Rd b/man/dsListSymbols.Rd index 352aba5..31de995 100644 --- a/man/dsListSymbols.Rd +++ b/man/dsListSymbols.Rd @@ -9,6 +9,9 @@ dsListSymbols(conn) \arguments{ \item{conn}{An object that inherits from \code{\link{DSConnection-class}}.} } +\value{ +A character vector of symbol names. +} \description{ After assignments have been performed, some symbols live in the DataSHIELD R session on the server side. } @@ -31,6 +34,7 @@ Other DSConnection generics: \code{\link{dsDisconnect}()}, \code{\link{dsGetInfo}()}, \code{\link{dsHasResource}()}, +\code{\link{dsHasSession}()}, \code{\link{dsHasTable}()}, \code{\link{dsIsAsync}()}, \code{\link{dsKeepAlive}()}, @@ -43,6 +47,7 @@ Other DSConnection generics: \code{\link{dsRestoreWorkspace}()}, \code{\link{dsRmSymbol}()}, \code{\link{dsRmWorkspace}()}, -\code{\link{dsSaveWorkspace}()} +\code{\link{dsSaveWorkspace}()}, +\code{\link{dsSession}()} } \concept{DSConnection generics} diff --git a/man/dsListTables.Rd b/man/dsListTables.Rd index 36c42ff..aa257e8 100644 --- a/man/dsListTables.Rd +++ b/man/dsListTables.Rd @@ -34,6 +34,7 @@ Other DSConnection generics: \code{\link{dsDisconnect}()}, \code{\link{dsGetInfo}()}, \code{\link{dsHasResource}()}, +\code{\link{dsHasSession}()}, \code{\link{dsHasTable}()}, \code{\link{dsIsAsync}()}, \code{\link{dsKeepAlive}()}, @@ -46,6 +47,7 @@ Other DSConnection generics: \code{\link{dsRestoreWorkspace}()}, \code{\link{dsRmSymbol}()}, \code{\link{dsRmWorkspace}()}, -\code{\link{dsSaveWorkspace}()} +\code{\link{dsSaveWorkspace}()}, +\code{\link{dsSession}()} } \concept{DSConnection generics} diff --git a/man/dsListWorkspaces.Rd b/man/dsListWorkspaces.Rd index de32409..635b260 100644 --- a/man/dsListWorkspaces.Rd +++ b/man/dsListWorkspaces.Rd @@ -33,6 +33,7 @@ Other DSConnection generics: \code{\link{dsDisconnect}()}, \code{\link{dsGetInfo}()}, \code{\link{dsHasResource}()}, +\code{\link{dsHasSession}()}, \code{\link{dsHasTable}()}, \code{\link{dsIsAsync}()}, \code{\link{dsKeepAlive}()}, @@ -45,6 +46,7 @@ Other DSConnection generics: \code{\link{dsRestoreWorkspace}()}, \code{\link{dsRmSymbol}()}, \code{\link{dsRmWorkspace}()}, -\code{\link{dsSaveWorkspace}()} +\code{\link{dsSaveWorkspace}()}, +\code{\link{dsSession}()} } \concept{DSConnection generics} diff --git a/man/dsRestoreWorkspace.Rd b/man/dsRestoreWorkspace.Rd index 1e62045..dbca63b 100644 --- a/man/dsRestoreWorkspace.Rd +++ b/man/dsRestoreWorkspace.Rd @@ -34,6 +34,7 @@ Other DSConnection generics: \code{\link{dsDisconnect}()}, \code{\link{dsGetInfo}()}, \code{\link{dsHasResource}()}, +\code{\link{dsHasSession}()}, \code{\link{dsHasTable}()}, \code{\link{dsIsAsync}()}, \code{\link{dsKeepAlive}()}, @@ -46,6 +47,7 @@ Other DSConnection generics: \code{\link{dsListWorkspaces}()}, \code{\link{dsRmSymbol}()}, \code{\link{dsRmWorkspace}()}, -\code{\link{dsSaveWorkspace}()} +\code{\link{dsSaveWorkspace}()}, +\code{\link{dsSession}()} } \concept{DSConnection generics} diff --git a/man/dsRmSymbol.Rd b/man/dsRmSymbol.Rd index 2d5ad28..97292a2 100644 --- a/man/dsRmSymbol.Rd +++ b/man/dsRmSymbol.Rd @@ -33,6 +33,7 @@ Other DSConnection generics: \code{\link{dsDisconnect}()}, \code{\link{dsGetInfo}()}, \code{\link{dsHasResource}()}, +\code{\link{dsHasSession}()}, \code{\link{dsHasTable}()}, \code{\link{dsIsAsync}()}, \code{\link{dsKeepAlive}()}, @@ -45,6 +46,7 @@ Other DSConnection generics: \code{\link{dsListWorkspaces}()}, \code{\link{dsRestoreWorkspace}()}, \code{\link{dsRmWorkspace}()}, -\code{\link{dsSaveWorkspace}()} +\code{\link{dsSaveWorkspace}()}, +\code{\link{dsSession}()} } \concept{DSConnection generics} diff --git a/man/dsRmWorkspace.Rd b/man/dsRmWorkspace.Rd index b4e627c..b0d41bf 100644 --- a/man/dsRmWorkspace.Rd +++ b/man/dsRmWorkspace.Rd @@ -36,6 +36,7 @@ Other DSConnection generics: \code{\link{dsDisconnect}()}, \code{\link{dsGetInfo}()}, \code{\link{dsHasResource}()}, +\code{\link{dsHasSession}()}, \code{\link{dsHasTable}()}, \code{\link{dsIsAsync}()}, \code{\link{dsKeepAlive}()}, @@ -48,6 +49,7 @@ Other DSConnection generics: \code{\link{dsListWorkspaces}()}, \code{\link{dsRestoreWorkspace}()}, \code{\link{dsRmSymbol}()}, -\code{\link{dsSaveWorkspace}()} +\code{\link{dsSaveWorkspace}()}, +\code{\link{dsSession}()} } \concept{DSConnection generics} diff --git a/man/dsSaveWorkspace.Rd b/man/dsSaveWorkspace.Rd index 0983307..79685c7 100644 --- a/man/dsSaveWorkspace.Rd +++ b/man/dsSaveWorkspace.Rd @@ -33,6 +33,7 @@ Other DSConnection generics: \code{\link{dsDisconnect}()}, \code{\link{dsGetInfo}()}, \code{\link{dsHasResource}()}, +\code{\link{dsHasSession}()}, \code{\link{dsHasTable}()}, \code{\link{dsIsAsync}()}, \code{\link{dsKeepAlive}()}, @@ -45,6 +46,7 @@ Other DSConnection generics: \code{\link{dsListWorkspaces}()}, \code{\link{dsRestoreWorkspace}()}, \code{\link{dsRmSymbol}()}, -\code{\link{dsRmWorkspace}()} +\code{\link{dsRmWorkspace}()}, +\code{\link{dsSession}()} } \concept{DSConnection generics} diff --git a/man/dsSession.Rd b/man/dsSession.Rd new file mode 100644 index 0000000..d4cd12f --- /dev/null +++ b/man/dsSession.Rd @@ -0,0 +1,58 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/DSConnection.R +\name{dsSession} +\alias{dsSession} +\title{Create a remote R session} +\usage{ +dsSession(conn, async = TRUE) +} +\arguments{ +\item{conn}{An object that inherits from \code{\link{DSConnection-class}}.} + +\item{async}{Whether the result of the call should be retrieved asynchronously. When TRUE (default) +the calls are parallelized over the connections, when the connection supports +that feature, with an extra overhead of requests.} +} +\value{ +An object of class \code{\link{DSSession-class}} representing the remote R session. +} +\description{ +Create a remote R session if none exists. If a remote R session already exists, +it will be reused. Returns a logical indicating if a remote R session exists +accessible through this connection. +} +\examples{ +\dontrun{ +con <- dsConnect(DSOpal::Opal(), "server1", + username = "dsuser", password = "password", url = "https://opal-demo.obiba.org") +dsSession(con, async=TRUE) +dsDisconnect(con) +} +} +\seealso{ +Other DSConnection generics: +\code{\link{DSConnection-class}}, +\code{\link{dsAggregate}()}, +\code{\link{dsAssignExpr}()}, +\code{\link{dsAssignResource}()}, +\code{\link{dsAssignTable}()}, +\code{\link{dsDisconnect}()}, +\code{\link{dsGetInfo}()}, +\code{\link{dsHasResource}()}, +\code{\link{dsHasSession}()}, +\code{\link{dsHasTable}()}, +\code{\link{dsIsAsync}()}, +\code{\link{dsKeepAlive}()}, +\code{\link{dsListMethods}()}, +\code{\link{dsListPackages}()}, +\code{\link{dsListProfiles}()}, +\code{\link{dsListResources}()}, +\code{\link{dsListSymbols}()}, +\code{\link{dsListTables}()}, +\code{\link{dsListWorkspaces}()}, +\code{\link{dsRestoreWorkspace}()}, +\code{\link{dsRmSymbol}()}, +\code{\link{dsRmWorkspace}()}, +\code{\link{dsSaveWorkspace}()} +} +\concept{DSConnection generics} diff --git a/man/dsStateMessage.Rd b/man/dsStateMessage.Rd new file mode 100644 index 0000000..c85788c --- /dev/null +++ b/man/dsStateMessage.Rd @@ -0,0 +1,39 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/DSSession.R +\name{dsStateMessage} +\alias{dsStateMessage} +\title{Get the state of the remote R session} +\usage{ +dsStateMessage(session) +} +\arguments{ +\item{session}{An object inheriting from \code{\link{DSSession-class}}.} +} +\value{ +A character string +} +\description{ +Get a human-readable message that informs about the state of the remote R session. +The primary use of this function is to inform the user about the session state process +after it has been created in an asynchronous way. +} +\examples{ +\dontrun{ +con <- dsConnect(DSOpal::Opal(), "server1", + username = "dsuser", password = "password", url = "https://opal-demo.obiba.org") +session <- dsSession(con, async = TRUE) +ready <- dsIsReady(session) +while (!ready) { + Sys.sleep(1) + ready <- dsIsReady(session) + cat(dsStateMessage(session), "\n") +} +dsDisconnect(con) +} +} +\seealso{ +Other DSSession generics: +\code{\link{DSSession-class}}, +\code{\link{dsIsReady}()} +} +\concept{DSSession generics}