Merge branch 'master' of git.curoverse.com:arvados into 11876-r-sdk
[arvados.git] / sdk / R / R / RESTService.R
1 RESTService <- R6::R6Class(
2
3     "RESTService",
4
5     public = list(
6
7         hostName       = NULL,
8         token          = NULL,
9         http           = NULL,
10         httpParser     = NULL,
11
12         initialize = function(token, hostName, webDavHostName = NULL,  http, httpParser)
13         {
14             version <- "v1"
15
16             self$token       <- token
17             self$hostName    <- paste0("https://", hostName,
18                                        "/arvados/", version, "/")
19             self$http        <- http
20             self$httpParser  <- httpParser
21
22             private$rawHostName    <- hostName
23             private$webDavHostName <- webDavHostName
24         },
25
26         getWebDavHostName = function()
27         {
28             if(is.null(private$webDavHostName))
29             {
30                 discoveryDocumentURL <- paste0("https://", private$rawHostName,
31                                                "/discovery/v1/apis/arvados/v1/rest")
32
33                 headers <- list(Authorization = paste("OAuth2", self$token))
34
35                 serverResponse <- self$http$GET(discoveryDocumentURL, headers)
36
37                 discoveryDocument <- self$httpParser$parseJSONResponse(serverResponse)
38                 private$webDavHostName <- discoveryDocument$keepWebServiceUrl
39
40                 if(is.null(private$webDavHostName))
41                     stop("Unable to find WebDAV server.")
42             }
43
44             private$webDavHostName
45         },
46
47         getResource = function(resource, uuid)
48         {
49             resourceURL <- paste0(self$hostName, resource, "/", uuid)
50             headers <- list(Authorization = paste("OAuth2", self$token))
51
52             serverResponse <- self$http$GET(resourceURL, headers)
53
54             resource <- self$httpParser$parseJSONResponse(serverResponse)
55
56             if(!is.null(resource$errors))
57                 stop(resource$errors)
58
59             resource
60         },
61
62         listResources = function(resource, filters = NULL, limit = 100, offset = 0)
63         {
64             resourceURL <- paste0(self$hostName, resource)
65             headers <- list(Authorization = paste("OAuth2", self$token))
66
67             serverResponse <- self$http$GET(resourceURL, headers, filters,
68                                             limit, offset)
69
70             resources <- self$httpParser$parseJSONResponse(serverResponse)
71
72             if(!is.null(resources$errors))
73                 stop(resources$errors)
74
75             resources
76         },
77
78         fetchAllItems = function(resourceURL, filters)
79         {
80             headers <- list(Authorization = paste("OAuth2", self$token))
81
82             offset <- 0
83             itemsAvailable <- .Machine$integer.max
84             items <- c()
85             while(length(items) < itemsAvailable)
86             {
87                 serverResponse <- self$http$GET(url          = resourceURL,
88                                                 headers      = headers,
89                                                 queryFilters = filters,
90                                                 limit        = NULL,
91                                                 offset       = offset)
92
93                 parsedResponse <- self$httpParser$parseJSONResponse(serverResponse)
94
95                 if(!is.null(parsedResponse$errors))
96                     stop(parsedResponse$errors)
97
98                 items          <- c(items, parsedResponse$items)
99                 offset         <- length(items)
100                 itemsAvailable <- parsedResponse$items_available
101             }
102
103             items
104         },
105
106         deleteResource = function(resource, uuid)
107         {
108             collectionURL <- paste0(self$hostName, resource, "/", uuid)
109             headers <- list("Authorization" = paste("OAuth2", self$token),
110                             "Content-Type"  = "application/json")
111
112             serverResponse <- self$http$DELETE(collectionURL, headers)
113
114             removedResource <- self$httpParser$parseJSONResponse(serverResponse)
115
116             if(!is.null(removedResource$errors))
117                 stop(removedResource$errors)
118
119             removedResource
120         },
121
122         updateResource = function(resource, uuid, newContent)
123         {
124             resourceURL <- paste0(self$hostName, resource, "/", uuid)
125             headers <- list("Authorization" = paste("OAuth2", self$token),
126                             "Content-Type"  = "application/json")
127
128             newContent <- jsonlite::toJSON(newContent, auto_unbox = T)
129
130             serverResponse <- self$http$PUT(resourceURL, headers, newContent)
131
132             updatedResource <- self$httpParser$parseJSONResponse(serverResponse)
133
134             if(!is.null(updatedResource$errors))
135                 stop(updatedResource$errors)
136
137             updatedResource
138         },
139
140         createResource = function(resource, content)
141         {
142             resourceURL <- paste0(self$hostName, resource)
143             headers <- list("Authorization" = paste("OAuth2", self$token),
144                             "Content-Type"  = "application/json")
145
146             content <- jsonlite::toJSON(content, auto_unbox = T)
147
148             serverResponse <- self$http$POST(resourceURL, headers, content)
149
150             newResource <- self$httpParser$parseJSONResponse(serverResponse)
151
152             if(!is.null(newResource$errors))
153                 stop(newResource$errors)
154
155             newResource
156         },
157
158         create = function(files, uuid)
159         {
160             sapply(files, function(filePath)
161             {
162                 private$createNewFile(filePath, uuid, "text/html")
163             })
164         },
165
166         delete = function(relativePath, uuid)
167         {
168             fileURL <- paste0(self$getWebDavHostName(), "c=",
169                               uuid, "/", relativePath);
170             headers <- list(Authorization = paste("OAuth2", self$token)) 
171
172             serverResponse <- self$http$DELETE(fileURL, headers)
173
174             if(serverResponse$status_code < 200 || serverResponse$status_code >= 300)
175                 stop(paste("Server code:", serverResponse$status_code))
176
177             serverResponse
178         },
179
180         move = function(from, to, uuid)
181         {
182             collectionURL <- paste0(self$getWebDavHostName(), "c=", uuid, "/")
183             fromURL <- paste0(collectionURL, from)
184             toURL <- paste0(collectionURL, to)
185
186             headers <- list("Authorization" = paste("OAuth2", self$token),
187                            "Destination" = toURL)
188
189             serverResponse <- self$http$MOVE(fromURL, headers)
190
191             if(serverResponse$status_code < 200 || serverResponse$status_code >= 300)
192                 stop(paste("Server code:", serverResponse$status_code))
193
194             serverResponse
195         },
196
197         getCollectionContent = function(uuid)
198         {
199             collectionURL <- URLencode(paste0(self$getWebDavHostName(),
200                                               "c=", uuid))
201
202             headers <- list("Authorization" = paste("OAuth2", self$token))
203
204             response <- self$http$PROPFIND(collectionURL, headers)
205
206             if(all(response == ""))
207                 stop("Response is empty, request may be misconfigured")
208
209             if(response$status_code < 200 || response$status_code >= 300)
210                 stop(paste("Server code:", response$status_code))
211
212             self$httpParser$getFileNamesFromResponse(response, collectionURL)
213         },
214
215         getResourceSize = function(relativePath, uuid)
216         {
217             collectionURL <- URLencode(paste0(self$getWebDavHostName(),
218                                               "c=", uuid))
219
220             subcollectionURL <- paste0(collectionURL, "/", relativePath);
221
222             headers <- list("Authorization" = paste("OAuth2", self$token))
223
224             response <- self$http$PROPFIND(subcollectionURL, headers)
225
226             if(all(response == ""))
227                 stop("Response is empty, request may be misconfigured")
228
229             if(response$status_code < 200 || response$status_code >= 300)
230                 stop(paste("Server code:", response$status_code))
231
232             sizes <- self$httpParser$getFileSizesFromResponse(response,
233                                                               collectionURL)
234             as.numeric(sizes)
235         },
236
237         read = function(relativePath, uuid, contentType = "raw", offset = 0, length = 0)
238         {
239             fileURL <- paste0(self$getWebDavHostName(),
240                              "c=", uuid, "/", relativePath);
241
242             range <- paste0("bytes=", offset, "-")
243
244             if(length > 0)
245                 range = paste0(range, offset + length - 1)
246
247             if(offset == 0 && length == 0)
248             {
249                 headers <- list(Authorization = paste("OAuth2", self$token))
250             }
251             else
252             {
253                 headers <- list(Authorization = paste("OAuth2", self$token),
254                                 Range = range)
255             }
256
257             if(!(contentType %in% self$httpParser$validContentTypes))
258                 stop("Invalid contentType. Please use text or raw.")
259
260             serverResponse <- self$http$GET(fileURL, headers)
261
262             if(serverResponse$status_code < 200 || serverResponse$status_code >= 300)
263                 stop(paste("Server code:", serverResponse$status_code))
264
265             self$httpParser$parseResponse(serverResponse, contentType)
266         },
267
268         write = function(relativePath, uuid, content, contentType)
269         {
270             fileURL <- paste0(self$getWebDavHostName(),
271                              "c=", uuid, "/", relativePath);
272             headers <- list(Authorization = paste("OAuth2", self$token),
273                             "Content-Type" = contentType)
274             body <- content
275
276             serverResponse <- self$http$PUT(fileURL, headers, body)
277
278             if(serverResponse$status_code < 200 || serverResponse$status_code >= 300)
279                 stop(paste("Server code:", serverResponse$status_code))
280
281             self$httpParser$parseResponse(serverResponse, "text")
282         },
283
284         getConnection = function(uuid, relativePath, openMode)
285         {
286             fileURL <- paste0(self$getWebDavHostName(), 
287                               "c=", uuid, "/", relativePath);
288             headers <- list(Authorization = paste("OAuth2", self$token))
289
290             h <- curl::new_handle()
291             curl::handle_setheaders(h, .list = headers)
292
293             conn <- curl::curl(url = fileURL, open = openMode, handle = h)
294
295             conn
296         }
297     ),
298
299     private = list(
300
301         webDavHostName = NULL,
302         rawHostName    = NULL,
303
304         createNewFile = function(relativePath, uuid, contentType)
305         {
306             fileURL <- paste0(self$getWebDavHostName(), "c=",
307                               uuid, "/", relativePath)
308             headers <- list(Authorization = paste("OAuth2", self$token), 
309                             "Content-Type" = contentType)
310             body <- NULL
311
312             serverResponse <- self$http$PUT(fileURL, headers, body)
313
314             if(serverResponse$status_code < 200 || serverResponse$status_code >= 300)
315                 stop(paste("Server code:", serverResponse$status_code))
316
317             paste("File created:", relativePath)
318         }
319     ),
320
321     cloneable = FALSE
322 )