Merge branch 'master' into 7478-anm-spot-instances
[arvados.git] / sdk / R / R / HttpRequest.R
index 041d64d825fe9e842b87c2d97e5e353b04c2238b..95dd375debe5ce076638c55de49a57db1f2d8f0d 100644 (file)
-source("./R/custom_classes.R")
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
 
-HttpRequest <- setRefClass(
+source("./R/util.R")
 
-    "HttrRequest",
-
-    fields = list(
-        send_method         = "character",
-        server_base_url     = "character",
-        server_relative_url = "character",
-        auth_token          = "character",
-        allowed_methods     = "list",
-        request_body        = "ANY",
-        query_filters       = "ANY",
-        response_limit      = "ANY",
-        query_offset        = "ANY"
-    ),
-
-    methods = list(
-        initialize = function(method,
-                              token,
-                              base_url,
-                              relative_url,
-                              body = NULL,
-                              filters = NULL,
-                              limit = 100,
-                              offset = 0) 
-        {
-            send_method         <<- method
-            auth_token          <<- token
-            server_base_url     <<- base_url
-            server_relative_url <<- relative_url
-            request_body        <<- body
-            query_filters       <<- filters
-            response_limit      <<- limit
-            query_offset        <<- offset
-        },
+HttpRequest <- R6::R6Class(
 
-        execute = function() 
-        {
-            #Todo(Fudo): Get rid of the switch and make this module more general.
-            http_method <- switch(send_method,
-                                  "GET"    = .self$getRequest,
-                                  "POST"   = .self$postRequest,
-                                  "PUT"    = .self$putRequest,
-                                  "DELETE" = .self$deleteRequest,
-                                  "PATCH"  = .self$pathcRequest)
-            http_method()
-        },
+    "HttrRequest",
 
-        getRequest = function() 
-        {
-            requestHeaders <- httr::add_headers(Authorization = .self$getAuthHeader())
-            requestQuery   <- .self$generateQuery()
-            url            <- paste0(server_base_url, server_relative_url, requestQuery)
+    public = list(
 
-            server_data <- httr::GET(url    = url,
-                                     config = requestHeaders)
-        },
+        validContentTypes = NULL,
+        validVerbs = NULL,
 
-        #Todo(Fudo): Try to make this more generic
-        postRequest = function() 
+        initialize = function() 
         {
-            url <- paste0(server_base_url, server_relative_url)
-            requestHeaders <- httr::add_headers("Authorization" = .self$getAuthHeader(),
-                                                "Content-Type"  = "application/json")
-            response <- POST(url, body = request_body, config = requestHeaders)
+            self$validContentTypes <- c("text", "raw")
+            self$validVerbs <- c("GET", "POST", "PUT", "DELETE", "PROPFIND", "MOVE")
         },
 
-        putRequest = function() 
+        exec = function(verb, url, headers = NULL, body = NULL, queryParams = NULL,
+                        retryTimes = 0)
         {
-            url <- paste0(server_base_url, server_relative_url)
-            requestHeaders <- httr::add_headers("Authorization" = .self$getAuthHeader(),
-                                                "Content-Type"  = "application/json")
-
-            response <- PUT(url, body = request_body, config = requestHeaders)
-        },
+            if(!(verb %in% self$validVerbs))
+                stop("Http verb is not valid.")
 
-        deleteRequest = function() 
-        {
-            url <- paste0(server_base_url, server_relative_url)
-            requestHeaders <- httr::add_headers("Authorization" = .self$getAuthHeader(),
-                                                "Content-Type"  = "application/json")
-            response <- DELETE(url, config = requestHeaders)
-        },
+            urlQuery <- self$createQuery(queryParams)
+            url      <- paste0(url, urlQuery)
 
-        pathcRequest = function() 
-        {
-            #Todo(Fudo): Implement this later on.
-            print("PATCH method")
-        },
+            config <- httr::add_headers(unlist(headers))
+            if(toString(Sys.getenv("ARVADOS_API_HOST_INSECURE") == "TRUE"))
+               config$options = list(ssl_verifypeer = FALSE)
 
-        getAuthHeader = function() 
-        {
-            auth_method <- "OAuth2"
-            auth_header <- paste(auth_method, auth_token)
+            # times = 1 regular call + numberOfRetries
+            response <- httr::RETRY(verb, url = url, body = body,
+                                    config = config, times = retryTimes + 1)
         },
 
-        generateQuery = function() 
+        createQuery = function(queryParams)
         {
-            #Todo(Fudo): This function is a mess, refactor it
-            finalQuery <- "?alt=json"
+            queryParams <- Filter(Negate(is.null), queryParams)
 
-            if(!is.null(query_filters))
+            query <- sapply(queryParams, function(param)
             {
-                filters <- sapply(query_filters, function(filter)
-                {
-                    if(length(filter) != 3)
-                        stop("Filter list must have exacthey 3 elements.")
-
-                    attributeAndOperator = filter[c(1, 2)]
-                    filterList = filter[[3]]
-                    filterListIsPrimitive = TRUE
-                    if(length(filterList) > 1)
-                        filterListIsPrimitive = FALSE
-
-                    attributeAndOperator <- sapply(attributeAndOperator, function(component) {
-                        component <- paste0("\"", component, "\"")
-                    })
-
-                    filterList <- sapply(unlist(filterList), function(filter) {
-                        filter <- paste0("\"", filter, "\"")
-                    })
-
-                    filterList <- paste(filterList, collapse = ",+")
-
-                    if(!filterListIsPrimitive)
-                        filterList <- paste0("[", filterList, "]")
-
-                    filter <- c(attributeAndOperator, filterList)
+                if(is.list(param) || length(param) > 1)
+                    param <- RListToPythonList(param, ",")
 
-                    queryParameter <- paste(filter, collapse = ",+")
-                    queryParameter <- paste0("[", queryParameter, "]")
-        
-                })
+                URLencode(as.character(param), reserved = T, repeated = T)
 
-                filters <- paste(filters, collapse = ",+")
-                filters <- paste0("[", filters, "]")
+            }, USE.NAMES = TRUE)
 
-                encodedQuery <- URLencode(filters, reserved = T, repeated = T)
-
-                finalQuery <- paste0(finalQuery, "&filters=", encodedQuery)
-
-                #Todo(Fudo): This is a hack for now. Find a proper solution.
-                finalQuery <- stringr::str_replace_all(finalQuery, "%2B", "+")
-            }
-
-            if(!is.null(response_limit))
+            if(length(query) > 0)
             {
-                if(!is.numeric(response_limit))
-                    stop("Limit must be a numeric type.")
-                
-                finalQuery <- paste0(finalQuery, "&limit=", response_limit)
-            }
+                query <- paste0(names(query), "=", query, collapse = "&")
 
-            if(!is.null(query_offset))
-            {
-                if(!is.numeric(query_offset))
-                    stop("Offset must be a numeric type.")
-                
-                finalQuery <- paste0(finalQuery, "&offset=", query_offset)
+                return(paste0("/?", query))
             }
 
-            finalQuery
+            return("")
         }
-    )
+    ),
+
+    cloneable = FALSE
 )