Skip to content

Commit 91d054d

Browse files
move upload logic to createUploadSession and uploadToSession functions
1 parent 6c9e872 commit 91d054d

File tree

1 file changed

+73
-43
lines changed

1 file changed

+73
-43
lines changed

DriveBackup/src/main/java/ratismal/drivebackup/uploaders/onedrive/OneDriveUploader.java

Lines changed: 73 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -141,50 +141,9 @@ public void uploadFile(File file, String location) throws IOException {
141141
String destinationRoot = normalizePath(ConfigParser.getConfig().backupStorage.remoteDirectory);
142142
String destinationPath = concatPath(destinationRoot, location);
143143
FQID destinationId = createPath(destinationPath);
144-
Request request = new Request.Builder()
145-
.addHeader("Authorization", "Bearer " + accessToken)
146-
.url("https://graph.microsoft.com/v1.0/drives/" + destinationId.driveId
147-
+ "/items/" + destinationId.itemId+ ":/" + file.getName() + ":/createUploadSession")
148-
.post(RequestBody.create("{}", jsonMediaType))
149-
.build();
150-
JSONObject parsedResponse;
151-
try (Response response = DriveBackup.httpClient.newCall(request).execute()) {
152-
parsedResponse = new JSONObject(response.body().string());
153-
}
154-
String uploadURL = parsedResponse.getString("uploadUrl");
144+
String uploadURL = createUploadSession(file.getName(), destinationId);
155145
raf = new RandomAccessFile(file, "r");
156-
int exponentialBackoffMillis = EXPONENTIAL_BACKOFF_MILLIS_DEFAULT;
157-
int retryCount = 0;
158-
while (true) {
159-
byte[] bytesToUpload = getChunk();
160-
request = new Request.Builder()
161-
.addHeader("Content-Range", String.format("bytes %d-%d/%d", getTotalUploaded(), getTotalUploaded() + bytesToUpload.length - 1, file.length()))
162-
.url(uploadURL)
163-
.put(RequestBody.create(bytesToUpload, zipMediaType))
164-
.build();
165-
try (Response uploadResponse = DriveBackup.httpClient.newCall(request).execute()) {
166-
if (uploadResponse.code() == 202) {
167-
parsedResponse = new JSONObject(uploadResponse.body().string());
168-
List<Object> nextExpectedRanges = parsedResponse.getJSONArray("nextExpectedRanges").toList();
169-
setRanges(nextExpectedRanges.toArray(new String[0]));
170-
exponentialBackoffMillis = EXPONENTIAL_BACKOFF_MILLIS_DEFAULT;
171-
retryCount = 0;
172-
} else if (uploadResponse.code() == 201 || uploadResponse.code() == 200) {
173-
break;
174-
} else { // TODO conflict after successful upload not handled
175-
if (retryCount > MAX_RETRY_ATTEMPTS) {
176-
request = new Request.Builder().url(uploadURL).delete().build();
177-
DriveBackup.httpClient.newCall(request).execute().close();
178-
throw new IOException(String.format("Upload failed after %d retries. %d %s", MAX_RETRY_ATTEMPTS, uploadResponse.code(), uploadResponse.message()));
179-
}
180-
if (uploadResponse.code() >= 500 && uploadResponse.code() < 600) {
181-
Thread.sleep(exponentialBackoffMillis);
182-
exponentialBackoffMillis *= EXPONENTIAL_BACKOFF_FACTOR;
183-
}
184-
retryCount++;
185-
}
186-
}
187-
}
146+
uploadToSession(uploadURL, file.length());
188147
try {
189148
pruneBackups(destinationId);
190149
} catch (Exception e) {
@@ -464,6 +423,77 @@ private FQID uploadSmallFile(@NotNull File file, @NotNull FQID destinationFolder
464423
}
465424
}
466425

426+
/**
427+
* creates an upload session for a file in a destination folder on OneDrive.
428+
*
429+
* @param fileName of the file to upload
430+
* @param destinationFolder as FQID
431+
* @return String with the upload URL for the file
432+
* @throws IOException if there is an error executing the request
433+
* @throws GraphApiErrorException if the upload session was not created
434+
* @throws JSONException if the response does not contain the expected values
435+
*/
436+
@NotNull
437+
private String createUploadSession(@NotNull String fileName, @NotNull FQID destinationFolder) throws IOException, GraphApiErrorException {
438+
Request request = new Request.Builder()
439+
.addHeader("Authorization", "Bearer " + accessToken)
440+
.url("https://graph.microsoft.com/v1.0/drives/" + destinationFolder.driveId
441+
+ "/items/" + destinationFolder.itemId + ":/" + fileName + ":/createUploadSession")
442+
.post(RequestBody.create("{}", jsonMediaType))
443+
.build();
444+
try (Response response = DriveBackup.httpClient.newCall(request).execute()) {
445+
if (!response.isSuccessful()) {
446+
throw new GraphApiErrorException(response);
447+
}
448+
return new JSONObject(response.body().string()).getString("uploadUrl");
449+
}
450+
}
451+
452+
/**
453+
* uploads the file to a session with the given upload URL. some errors are handled via automatic retries.
454+
*
455+
* @param uploadURL of the upload session
456+
* @param fileSize of the file to upload
457+
* @throws IOException if a request could not be executed
458+
* @throws GraphApiErrorException with the last error after max retries
459+
* @throws InterruptedException if interrupted during retries
460+
*/
461+
private void uploadToSession(@NotNull String uploadURL, long fileSize)
462+
throws IOException, GraphApiErrorException, InterruptedException {
463+
int exponentialBackoffMillis = EXPONENTIAL_BACKOFF_MILLIS_DEFAULT;
464+
int retryCount = 0;
465+
while (true) {
466+
byte[] bytesToUpload = getChunk();
467+
Request uploadRequest = new Request.Builder()
468+
.addHeader("Content-Range", String.format("bytes %d-%d/%d", getTotalUploaded(), getTotalUploaded() + bytesToUpload.length - 1, fileSize))
469+
.url(uploadURL)
470+
.put(RequestBody.create(bytesToUpload, zipMediaType))
471+
.build();
472+
try (Response uploadResponse = DriveBackup.httpClient.newCall(uploadRequest).execute()) {
473+
if (uploadResponse.code() == 202) {
474+
JSONObject parsedResponse = new JSONObject(uploadResponse.body().string());
475+
List<Object> nextExpectedRanges = parsedResponse.getJSONArray("nextExpectedRanges").toList();
476+
setRanges(nextExpectedRanges.toArray(new String[0]));
477+
exponentialBackoffMillis = EXPONENTIAL_BACKOFF_MILLIS_DEFAULT;
478+
retryCount = 0;
479+
} else if (uploadResponse.code() == 201 || uploadResponse.code() == 200) {
480+
break;
481+
} else { // TODO conflict after successful upload not handled
482+
if (retryCount > MAX_RETRY_ATTEMPTS) {
483+
Request cancelRequest = new Request.Builder().url(uploadURL).delete().build();
484+
DriveBackup.httpClient.newCall(cancelRequest).execute().close();
485+
throw new GraphApiErrorException(uploadResponse);
486+
}
487+
if (uploadResponse.code() >= 500 && uploadResponse.code() < 600) {
488+
TimeUnit.MILLISECONDS.sleep(exponentialBackoffMillis);
489+
exponentialBackoffMillis *= EXPONENTIAL_BACKOFF_FACTOR;
490+
}
491+
retryCount++;
492+
}
493+
}
494+
}
495+
}
496+
467497
/**
468498
* Deletes the oldest files in the specified folder past the number to retain from the authenticated user's OneDrive.
469499
* <p>

0 commit comments

Comments
 (0)