X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/7da8eaf51a23ab23369b6e65f0634448cc4aeb3b..9bb169138470dbb176af7e891d6da2089950354b:/sdk/R/R/ArvadosFile.R diff --git a/sdk/R/R/ArvadosFile.R b/sdk/R/R/ArvadosFile.R index 563eaa2994..e28ba9606c 100644 --- a/sdk/R/R/ArvadosFile.R +++ b/sdk/R/R/ArvadosFile.R @@ -1,98 +1,270 @@ -#' ArvadosFile Object +source("./R/util.R") + +#' ArvadosFile +#' +#' ArvadosFile class represents a file inside Arvados collection. +#' +#' @section Usage: +#' \preformatted{file = ArvadosFile$new(name)} +#' +#' @section Arguments: +#' \describe{ +#' \item{name}{Name of the file.} +#' } +#' +#' @section Methods: +#' \describe{ +#' \item{getName()}{Returns name of the file.} +#' \item{getRelativePath()}{Returns file path relative to the root.} +#' \item{read(contentType = "raw", offset = 0, length = 0)}{Read file content.} +#' \item{write(content, contentType = "text/html")}{Write to file (override current content of the file).} +#' \item{connection(rw)}{Get connection opened in "read" or "write" mode.} +#' \item{flush()}{Write connections content to a file (override current content of the file).} +#' \item{remove(name)}{Removes ArvadosFile or Subcollection specified by name from the subcollection.} +#' \item{getSizeInBytes()}{Returns file size in bytes.} +#' \item{move(newLocation)}{Moves file to a new location inside collection.} +#' } +#' +#' @name ArvadosFile +#' @examples +#' \dontrun{ +#' myFile <- ArvadosFile$new("myFile") +#' +#' myFile$write("This is new file content") +#' fileContent <- myFile$read() +#' fileContent <- myFile$read("text") +#' fileContent <- myFile$read("raw", offset = 8, length = 4) #' -#' Update description +#' #Write a table: +#' arvConnection <- myFile$connection("w") +#' write.table(mytable, arvConnection) +#' arvadosFile$flush() #' -#' @export ArvadosFile +#' #Read a table: +#' arvConnection <- myFile$connection("r") +#' mytable <- read.table(arvConnection) +#' +#' myFile$move("newFolder/myFile") +#' } +NULL + +#' @export ArvadosFile <- R6::R6Class( "ArvadosFile", public = list( - initialize = function(name, relativePath, size, api, collection) + initialize = function(name) { - private$name <- name - private$size <- size - private$relativePath <- relativePath - private$api <- api - private$collection <- collection - private$http <- HttpRequest$new() - private$httpParser <- HttpParser$new() + if(name == "") + stop("Invalid name.") + + private$name <- name }, getName = function() private$name, - getRelativePath = function() private$relativePath, + getFileListing = function(fullpath = TRUE) + { + self$getName() + }, + + getSizeInBytes = function() + { + if(is.null(private$collection)) + return(0) + + REST <- private$collection$getRESTService() + + fileSize <- REST$getResourceSize(self$getRelativePath(), + private$collection$uuid) + + fileSize + }, + + get = function(fileLikeObjectName) + { + return(NULL) + }, + + getFirst = function() + { + return(NULL) + }, + + getCollection = function() private$collection, + + setCollection = function(collection) + { + private$collection <- collection + }, + + getRelativePath = function() + { + relativePath <- c(private$name) + parent <- private$parent + + while(!is.null(parent)) + { + relativePath <- c(parent$getName(), relativePath) + parent <- parent$getParent() + } + + relativePath <- relativePath[relativePath != ""] + paste0(relativePath, collapse = "/") + }, + + getParent = function() private$parent, - getSizeInBytes = function() private$size, + setParent = function(newParent) private$parent <- newParent, - read = function(offset = 0, length = 0) + read = function(contentType = "raw", offset = 0, length = 0) { + if(is.null(private$collection)) + stop("ArvadosFile doesn't belong to any collection.") + if(offset < 0 || length < 0) - stop("Offset and length must be positive values.") + stop("Offset and length must be positive values.") - range = paste0("bytes=", offset, "-") + REST <- private$collection$getRESTService() - if(length > 0) - range = paste0(range, offset + length - 1) - - fileURL = paste0(private$api$getWebDavHostName(), "c=", private$collection$uuid, "/", private$relativePath); - headers <- list(Authorization = paste("OAuth2", private$api$getToken()), - Range = range) + fileContent <- REST$read(self$getRelativePath(), + private$collection$uuid, + contentType, offset, length) + fileContent + }, - serverResponse <- private$http$GET(fileURL, headers) + connection = function(rw) + { + if (rw == "r" || rw == "rb") + { + REST <- private$collection$getRESTService() + return(REST$getConnection(private$collection$uuid, + self$getRelativePath(), + rw)) + } + else if (rw == "w") + { + private$buffer <- textConnection(NULL, "w") - if(serverResponse$status_code != 206) - stop(paste("Server code:", serverResponse$status_code)) + return(private$buffer) + } + }, - parsedServerResponse <- httr::content(serverResponse, "raw") - parsedServerResponse + flush = function() + { + v <- textConnectionValue(private$buffer) + close(private$buffer) + self$write(paste(v, collapse='\n')) }, - + write = function(content, contentType = "text/html") { - fileURL = paste0(private$api$getWebDavHostName(), "c=", private$collection$uuid, "/", private$relativePath); - headers <- list(Authorization = paste("OAuth2", private$api$getToken()), - "Content-Type" = contentType) - body <- content + if(is.null(private$collection)) + stop("ArvadosFile doesn't belong to any collection.") + + REST <- private$collection$getRESTService() + + writeResult <- REST$write(self$getRelativePath(), + private$collection$uuid, + content, contentType) + writeResult + }, + + move = function(newLocation) + { + if(is.null(private$collection)) + stop("ArvadosFile doesn't belong to any collection") + + newLocation <- trimFromEnd(newLocation, "/") + nameAndPath <- splitToPathAndName(newLocation) + + newParent <- private$collection$get(nameAndPath$path) - serverResponse <- private$http$PUT(fileURL, headers, body) + if(is.null(newParent)) + { + stop("Unable to get destination subcollection") + } - if(serverResponse$status_code != 201) - stop(paste("Server code:", serverResponse$status_code)) + childWithSameName <- newParent$get(nameAndPath$name) - private$notifyCollectionThatFileSizeChanges() + if(!is.null(childWithSameName)) + stop("Destination already contains content with same name.") - parsedServerResponse <- httr::content(serverResponse, "text") - parsedServerResponse + REST <- private$collection$getRESTService() + REST$move(self$getRelativePath(), + paste0(newParent$getRelativePath(), "/", nameAndPath$name), + private$collection$uuid) + + private$dettachFromCurrentParent() + private$attachToNewParent(newParent) + + private$name <- nameAndPath$name + + "Content moved successfully." } ), private = list( - name = NULL, - relativePath = NULL, - size = NULL, - parent = NULL, - api = NULL, - collection = NULL, - http = NULL, - httpParser = NULL, + name = NULL, + size = NULL, + parent = NULL, + collection = NULL, + buffer = NULL, - notifyCollectionThatFileSizeChanges = function() + attachToNewParent = function(newParent) { - collectionURL <- URLencode(paste0(private$api$getWebDavHostName(), "c=", private$collection$uuid)) - fileURL = paste0(collectionURL, "/", private$relativePath); - headers = list("Authorization" = paste("OAuth2", private$api$getToken())) + #Note: We temporary set parents collection to NULL. This will ensure that + # add method doesn't post file on REST. + parentsCollection <- newParent$getCollection() + newParent$setCollection(NULL, setRecursively = FALSE) + + newParent$add(self) + + newParent$setCollection(parentsCollection, setRecursively = FALSE) + + private$parent <- newParent + }, - propfindResponse <- private$http$PROPFIND(fileURL, headers) + dettachFromCurrentParent = function() + { + #Note: We temporary set parents collection to NULL. This will ensure that + # remove method doesn't remove this subcollection from REST. + parent <- private$parent + parentsCollection <- parent$getCollection() + parent$setCollection(NULL, setRecursively = FALSE) - fileInfo <- private$httpParser$parseWebDAVResponse(propfindResponse, collectionURL) + parent$remove(private$name) - private$size <- fileInfo[[1]]$fileSize - private$collection$update(self, "File size changed") + parent$setCollection(parentsCollection, setRecursively = FALSE) } ), - + cloneable = FALSE ) + +#' print.ArvadosFile +#' +#' Custom print function for ArvadosFile class +#' +#' @param x Instance of ArvadosFile class +#' @param ... Optional arguments. +#' @export +print.ArvadosFile = function(x, ...) +{ + collection <- NULL + relativePath <- x$getRelativePath() + + if(!is.null(x$getCollection())) + { + collection <- x$getCollection()$uuid + relativePath <- paste0("/", relativePath) + } + + cat(paste0("Type: ", "\"", "ArvadosFile", "\""), sep = "\n") + cat(paste0("Name: ", "\"", x$getName(), "\""), sep = "\n") + cat(paste0("Relative path: ", "\"", relativePath, "\""), sep = "\n") + cat(paste0("Collection: ", "\"", collection, "\""), sep = "\n") +}