Merge branch 'master' into 13822-nm-delayed-daemon
[arvados.git] / sdk / R / R / RESTService.R
index d65ef0f2d8828812d45886cf5b9860160db8ff17..ac65d0df3f37b6baa6031bc8cbab71b163e27a76 100644 (file)
@@ -1,14 +1,57 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+
 RESTService <- R6::R6Class(
 
     "RESTService",
 
     public = list(
 
-        initialize = function(api)
+        token      = NULL,
+        http       = NULL,
+        httpParser = NULL,
+        numRetries = NULL,
+
+        initialize = function(token, rawHost,
+                              http, httpParser,
+                              numRetries     = 0,
+                              webDavHostName = NULL)
+        {
+            self$token      <- token
+            self$http       <- http
+            self$httpParser <- httpParser
+            self$numRetries <- numRetries
+
+            private$rawHostName    <- rawHost
+            private$webDavHostName <- webDavHostName
+        },
+
+        setNumConnRetries = function(newNumOfRetries)
+        {
+            self$numRetries <- newNumOfRetries
+        },
+
+        getWebDavHostName = function()
         {
-            private$api <- api
-            private$http <- api$getHttpClient()
-            private$httpParser <- api$getHttpParser()
+            if(is.null(private$webDavHostName))
+            {
+                discoveryDocumentURL <- paste0("https://", private$rawHostName,
+                                               "/discovery/v1/apis/arvados/v1/rest")
+
+                headers <- list(Authorization = paste("OAuth2", self$token))
+
+                serverResponse <- self$http$exec("GET", discoveryDocumentURL, headers,
+                                                 retryTimes = self$numRetries)
+
+                discoveryDocument <- self$httpParser$parseJSONResponse(serverResponse)
+                private$webDavHostName <- discoveryDocument$keepWebServiceUrl
+
+                if(is.null(private$webDavHostName))
+                    stop("Unable to find WebDAV server.")
+            }
+
+            private$webDavHostName
         },
 
         create = function(files, uuid)
@@ -21,30 +64,30 @@ RESTService <- R6::R6Class(
 
         delete = function(relativePath, uuid)
         {
-            fileURL <- paste0(private$api$getWebDavHostName(), "c=",
+            fileURL <- paste0(self$getWebDavHostName(), "c=",
                               uuid, "/", relativePath);
-            headers <- list(Authorization = paste("OAuth2", private$api$getToken())) 
+            headers <- list(Authorization = paste("OAuth2", self$token)) 
 
-            serverResponse <- private$http$DELETE(fileURL, headers)
+            serverResponse <- self$http$exec("DELETE", fileURL, headers,
+                                             retryTimes = self$numRetries)
 
             if(serverResponse$status_code < 200 || serverResponse$status_code >= 300)
                 stop(paste("Server code:", serverResponse$status_code))
 
-            print(paste("File deleted:", relativePath))
+            serverResponse
         },
 
         move = function(from, to, uuid)
         {
-            #Todo Do we need this URLencode?
-            collectionURL <- URLencode(paste0(private$api$getWebDavHostName(), "c=",
-                                              uuid, "/"))
+            collectionURL <- paste0(self$getWebDavHostName(), "c=", uuid, "/")
             fromURL <- paste0(collectionURL, from)
             toURL <- paste0(collectionURL, to)
 
-            headers <- list("Authorization" = paste("OAuth2", private$api$getToken()),
+            headers <- list("Authorization" = paste("OAuth2", self$token),
                            "Destination" = toURL)
 
-            serverResponse <- private$http$MOVE(fromURL, headers)
+            serverResponse <- self$http$exec("MOVE", fromURL, headers,
+                                             retryTimes = self$numRetries)
 
             if(serverResponse$status_code < 200 || serverResponse$status_code >= 300)
                 stop(paste("Server code:", serverResponse$status_code))
@@ -54,57 +97,130 @@ RESTService <- R6::R6Class(
 
         getCollectionContent = function(uuid)
         {
-            collectionURL <- URLencode(paste0(private$api$getWebDavHostName(), "c=", uuid))
+            collectionURL <- URLencode(paste0(self$getWebDavHostName(),
+                                              "c=", uuid))
+
+            headers <- list("Authorization" = paste("OAuth2", self$token))
+
+            response <- self$http$exec("PROPFIND", collectionURL, headers,
+                                       retryTimes = self$numRetries)
 
-            headers = list("Authorization" = paste("OAuth2", private$api$getToken()))
+            if(all(response == ""))
+                stop("Response is empty, request may be misconfigured")
 
-            response <- private$http$PROPFIND(collectionURL, headers)
+            if(response$status_code < 200 || response$status_code >= 300)
+                stop(paste("Server code:", response$status_code))
 
-            parsedResponse <- private$httpParser$parseWebDAVResponse(response, collectionURL)
-            parsedResponse[-1]
+            self$httpParser$getFileNamesFromResponse(response, collectionURL)
         },
 
-        getResourceSize = function(uuid, relativePathToResource)
+        getResourceSize = function(relativePath, uuid)
         {
-            collectionURL <- URLencode(paste0(private$api$getWebDavHostName(),
+            collectionURL <- URLencode(paste0(self$getWebDavHostName(),
                                               "c=", uuid))
-            subcollectionURL <- paste0(collectionURL, "/",
-                                       relativePathToResource, "/");
 
-            headers = list("Authorization" = paste("OAuth2",
-                                                   private$api$getToken()))
+            subcollectionURL <- paste0(collectionURL, "/", relativePath);
+
+            headers <- list("Authorization" = paste("OAuth2", self$token))
+
+            response <- self$http$exec("PROPFIND", subcollectionURL, headers,
+                                       retryTimes = self$numRetries)
+
+            if(all(response == ""))
+                stop("Response is empty, request may be misconfigured")
+
+            if(response$status_code < 200 || response$status_code >= 300)
+                stop(paste("Server code:", response$status_code))
+
+            sizes <- self$httpParser$getFileSizesFromResponse(response,
+                                                              collectionURL)
+            as.numeric(sizes)
+        },
+
+        read = function(relativePath, uuid, contentType = "raw", offset = 0, length = 0)
+        {
+            fileURL <- paste0(self$getWebDavHostName(),
+                             "c=", uuid, "/", relativePath);
+
+            range <- paste0("bytes=", offset, "-")
+
+            if(length > 0)
+                range = paste0(range, offset + length - 1)
+
+            if(offset == 0 && length == 0)
+            {
+                headers <- list(Authorization = paste("OAuth2", self$token))
+            }
+            else
+            {
+                headers <- list(Authorization = paste("OAuth2", self$token),
+                                Range = range)
+            }
+
+            if(!(contentType %in% self$httpParser$validContentTypes))
+                stop("Invalid contentType. Please use text or raw.")
+
+            serverResponse <- self$http$exec("GET", fileURL, headers,
+                                             retryTimes = self$numRetries)
+
+            if(serverResponse$status_code < 200 || serverResponse$status_code >= 300)
+                stop(paste("Server code:", serverResponse$status_code))
+
+            self$httpParser$parseResponse(serverResponse, contentType)
+        },
+
+        write = function(relativePath, uuid, content, contentType)
+        {
+            fileURL <- paste0(self$getWebDavHostName(),
+                             "c=", uuid, "/", relativePath);
+            headers <- list(Authorization = paste("OAuth2", self$token),
+                            "Content-Type" = contentType)
+            body <- content
+
+            serverResponse <- self$http$exec("PUT", fileURL, headers, body,
+                                             retryTimes = self$numRetries)
+
+            if(serverResponse$status_code < 200 || serverResponse$status_code >= 300)
+                stop(paste("Server code:", serverResponse$status_code))
+
+            self$httpParser$parseResponse(serverResponse, "text")
+        },
+
+        getConnection = function(uuid, relativePath, openMode)
+        {
+            fileURL <- paste0(self$getWebDavHostName(), 
+                              "c=", uuid, "/", relativePath);
+            headers <- list(Authorization = paste("OAuth2", self$token))
 
-            propfindResponse <- private$http$PROPFIND(subcollectionURL, headers)
+            h <- curl::new_handle()
+            curl::handle_setheaders(h, .list = headers)
 
-            sizes <- private$httpParser$extractFileSizeFromWebDAVResponse(propfindResponse,
-                                                                          collectionURL)
-            sizes <- as.numeric(sizes[-1])
+            conn <- curl::curl(url = fileURL, open = openMode, handle = h)
 
-            return(sum(sizes))
+            conn
         }
     ),
 
     private = list(
 
-        api        = NULL,
-        http       = NULL,
-        httpParser = NULL,
-
+        webDavHostName = NULL,
+        rawHostName    = NULL,
 
         createNewFile = function(relativePath, uuid, contentType)
         {
-            fileURL <- paste0(private$api$getWebDavHostName(), "c=",
-                              uuid, "/", relativePath);
-            headers <- list(Authorization = paste("OAuth2", private$api$getToken()), 
+            fileURL <- paste0(self$getWebDavHostName(), "c=",
+                              uuid, "/", relativePath)
+            headers <- list(Authorization = paste("OAuth2", self$token), 
                             "Content-Type" = contentType)
             body <- NULL
 
-            serverResponse <- private$http$PUT(fileURL, headers, body)
+            serverResponse <- self$http$exec("PUT", fileURL, headers, body,
+                                             retryTimes = self$numRetries)
 
             if(serverResponse$status_code < 200 || serverResponse$status_code >= 300)
                 stop(paste("Server code:", serverResponse$status_code))
 
-            print(paste("File created:", relativePath))
+            paste("File created:", relativePath)
         }
     ),