Fix unhandled error exceptions that cause application to exit / crash when uploading files (Issue #624) (#625)

* Remove 'else throw e' which causes the application to exit / crash and replace with what the actual error message is from OneDrive
* Make logging of unhandled errors consistent
* Add extra error handling when uploading files for errors received from OneDrive or file system errors
* Flag that the upload failed if there is an exception error raised
* Update logging output for when an error occurs to indicate that the file was skipped
* Log the OneDrive response as log.vlog rather than log.error as it is now being handled correctly
* Throw an exception for 50x errors so that it gets caught correctly
* Clean up logging when exception is generated
This commit is contained in:
abraunegg 2019-08-24 15:54:48 +10:00 committed by GitHub
parent af07dea6f9
commit 488f756ecd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 406 additions and 103 deletions

View file

@ -802,22 +802,22 @@ final class OneDriveApi
case 500:
// No actions
log.vlog("OneDrive returned a 'HTTP 500 Internal Server Error' - gracefully handling error");
break;
throw new OneDriveException(http.statusLine.code, http.statusLine.reason, response);
case 502:
// No actions
log.vlog("OneDrive returned a 'HTTP 502 Bad Gateway Error' - gracefully handling error");
break;
throw new OneDriveException(http.statusLine.code, http.statusLine.reason, response);
case 503:
// No actions
log.vlog("OneDrive returned a 'HTTP 503 Service Unavailable Error' - gracefully handling error");
break;
throw new OneDriveException(http.statusLine.code, http.statusLine.reason, response);
case 504:
// No actions
log.vlog("OneDrive returned a 'HTTP 504 Gateway Timeout Error' - gracefully handling error");
break;
throw new OneDriveException(http.statusLine.code, http.statusLine.reason, response);
// Default - all other errors that are not a 2xx or a 302
default:

View file

@ -221,6 +221,8 @@ final class SyncEngine
private bool malwareDetected = false;
// download filesystem issue flag
private bool downloadFailed = false;
// upload failure - OneDrive or filesystem issue (reading data)
private bool uploadFailed = false;
// initialization has been done
private bool initDone = false;
// sync engine dryRun flag
@ -397,7 +399,6 @@ final class SyncEngine
log.vdebug("documentLibrary account type - flagging to disable upload validation checks due to Microsoft SharePoint file modification enrichments");
}
// download all new changes from OneDrive
void applyDifferences()
{
@ -674,16 +675,10 @@ final class SyncEngine
// Retry by calling applyDifferences() again
log.vlog("OneDrive returned a 'HTTP 504 - Gateway Timeout' - gracefully handling error");
applyDifferences(driveId, idToQuery);
}
else {
} else {
// Default operation if not 404, 410, 500, 504 errors
log.log("\n\nOneDrive returned an error with the following message:\n");
auto errorArray = splitLines(e.msg);
log.log("Error Message: ", errorArray[0]);
// extract 'message' as the reason
JSONValue errorMessage = parseJSON(replace(e.msg, errorArray[0], ""));
log.log("Error Reason: ", errorMessage["error"]["message"].str);
// display what the error is
displayOneDriveErrorMessage(e.msg);
log.log("\nRemove your '", cfg.databaseFilePath, "' file and try to sync again\n");
return;
}
@ -1226,7 +1221,8 @@ final class SyncEngine
}
} catch (std.exception.ErrnoException e) {
// There was a file system error
log.error("ERROR: ", e.msg);
// display the error message
displayFileSystemErrorMessage(e.msg);
downloadFailed = true;
return;
}
@ -1353,7 +1349,8 @@ final class SyncEngine
// Remove the path now that it is empty of children
rmdirRecurse(path);
} catch (FileException e) {
log.log(e.msg);
// display the error message
displayFileSystemErrorMessage(e.msg);
}
}
}
@ -1534,8 +1531,12 @@ final class SyncEngine
}
}
// upload local file system differences to OneDrive
private void uploadFileDifferences(Item item, string path)
{
// Reset upload failure - OneDrive or filesystem issue (reading data)
uploadFailed = false;
assert(item.type == ItemType.file);
if (exists(path)) {
if (isFile(path)) {
@ -1562,58 +1563,101 @@ final class SyncEngine
try {
response = onedrive.simpleUploadReplace(path, item.driveId, item.id, item.eTag);
} catch (OneDriveException e) {
if (e.httpStatusCode == 401) {
// OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded
writeln("skipped.");
log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error");
uploadFailed = true;
return;
}
if (e.httpStatusCode == 404) {
// HTTP request returned status code 404 - the eTag provided does not exist
// Delete record from the local database - file will be uploaded as a new file
writeln("skipped.");
log.vlog("OneDrive returned a 'HTTP 404 - eTag Issue' - gracefully handling error");
itemdb.deleteById(item.driveId, item.id);
uploadFailed = true;
return;
}
// Resolve https://github.com/abraunegg/onedrive/issues/36
if ((e.httpStatusCode == 409) || (e.httpStatusCode == 423)) {
// The file is currently checked out or locked for editing by another user
// We cant upload this file at this time
writeln(" skipped.");
writeln("skipped.");
log.fileOnly("Uploading modified file ", path, " ... skipped.");
write("", path, " is currently checked out or locked for editing by another user.");
log.fileOnly(path, " is currently checked out or locked for editing by another user.");
uploadFailed = true;
return;
}
if (e.httpStatusCode == 412) {
// HTTP request returned status code 412 - ETag does not match current item's value
// Delete record from the local database - file will be uploaded as a new file
writeln("skipped.");
log.vdebug("Simple Upload Replace Failed - OneDrive eTag / cTag match issue");
log.vlog("OneDrive returned a 'HTTP 412 - Precondition Failed' - gracefully handling error. Will upload as new file.");
itemdb.deleteById(item.driveId, item.id);
uploadFailed = true;
return;
}
if (e.httpStatusCode == 504) {
// HTTP request returned status code 504 (Gateway Timeout)
// Try upload as a session
response = session.upload(path, item.driveId, item.parentId, baseName(path), item.eTag);
} else {
// display what the error is
writeln("skipped.");
displayOneDriveErrorMessage(e.msg);
uploadFailed = true;
return;
}
else throw e;
} catch (FileException e) {
// display the error message
writeln("skipped.");
displayFileSystemErrorMessage(e.msg);
uploadFailed = true;
return;
}
// upload done without error
writeln("done.");
} else {
writeln("");
try {
response = session.upload(path, item.driveId, item.parentId, baseName(path), item.eTag);
} catch (OneDriveException e) {
} catch (OneDriveException e) {
if (e.httpStatusCode == 401) {
// OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded
writeln("skipped.");
log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error");
uploadFailed = true;
return;
}
if (e.httpStatusCode == 412) {
// HTTP request returned status code 412 - ETag does not match current item's value
// Delete record from the local database - file will be uploaded as a new file
writeln("skipped.");
log.vdebug("Simple Upload Replace Failed - OneDrive eTag / cTag match issue");
log.vlog("OneDrive returned a 'HTTP 412 - Precondition Failed' - gracefully handling error. Will upload as new file.");
itemdb.deleteById(item.driveId, item.id);
uploadFailed = true;
return;
} else {
// display what the error is
writeln("skipped.");
displayOneDriveErrorMessage(e.msg);
uploadFailed = true;
return;
}
} catch (FileException e) {
// display the error message
writeln("skipped.");
displayFileSystemErrorMessage(e.msg);
uploadFailed = true;
return;
}
// upload done without error
writeln("done.");
}
}
} else {
// OneDrive Business Account
// We need to always use a session to upload, but handle the changed file correctly
@ -1623,19 +1667,39 @@ final class SyncEngine
try {
response = session.upload(path, item.driveId, item.parentId, baseName(path), item.eTag);
} catch (OneDriveException e) {
if (e.httpStatusCode == 401) {
// OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded
writeln("skipped.");
log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error");
uploadFailed = true;
return;
}
// Resolve https://github.com/abraunegg/onedrive/issues/36
if ((e.httpStatusCode == 409) || (e.httpStatusCode == 423)) {
// The file is currently checked out or locked for editing by another user
// We cant upload this file at this time
writeln(" skipped.");
writeln("skipped.");
log.fileOnly("Uploading modified file ", path, " ... skipped.");
writeln("", path, " is currently checked out or locked for editing by another user.");
log.fileOnly(path, " is currently checked out or locked for editing by another user.");
uploadFailed = true;
return;
} else {
// display what the error is
writeln("skipped.");
displayOneDriveErrorMessage(e.msg);
uploadFailed = true;
return;
}
// what is this error?????
else throw e;
} catch (FileException e) {
// display the error message
writeln("skipped.");
displayFileSystemErrorMessage(e.msg);
uploadFailed = true;
return;
}
// upload done without error
writeln("done.");
// As the session.upload includes the last modified time, save the response
saveItem(response);
}
@ -1649,22 +1713,41 @@ final class SyncEngine
try {
response = session.upload(path, item.driveId, item.parentId, baseName(path), item.eTag);
} catch (OneDriveException e) {
if (e.httpStatusCode == 401) {
// OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded
writeln("skipped.");
log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error");
uploadFailed = true;
return;
}
// Resolve https://github.com/abraunegg/onedrive/issues/36
if ((e.httpStatusCode == 409) || (e.httpStatusCode == 423)) {
// The file is currently checked out or locked for editing by another user
// We cant upload this file at this time
writeln(" skipped.");
writeln("skipped.");
log.fileOnly("Uploading modified file ", path, " ... skipped.");
writeln("", path, " is currently checked out or locked for editing by another user.");
log.fileOnly(path, " is currently checked out or locked for editing by another user.");
uploadFailed = true;
return;
} else {
// display what the error is
writeln("skipped.");
displayOneDriveErrorMessage(e.msg);
uploadFailed = true;
return;
}
// what is this error?????
else throw e;
} catch (FileException e) {
// display the error message
writeln("skipped.");
displayFileSystemErrorMessage(e.msg);
uploadFailed = true;
return;
}
// upload done without error
writeln("done.");
// As the session.upload includes the last modified time, save the response
saveItem(response);
} else {
// Due to https://github.com/OneDrive/onedrive-api-docs/issues/935 Microsoft modifies all PDF, MS Office & HTML files with added XML content. It is a 'feature' of SharePoint.
// This means, as a session upload, on 'completion' the file is 'moved' and generates a 404 ......
@ -1677,9 +1760,6 @@ final class SyncEngine
return;
}
}
// log line completion
writeln("done.");
}
log.fileOnly("Uploading modified file ", path, " ... done.");
if ("cTag" in response) {
@ -1761,6 +1841,7 @@ final class SyncEngine
}
}
// upload new items to OneDrive
private void uploadNewItems(string path)
{
// https://support.microsoft.com/en-us/help/3125202/restrictions-and-limitations-when-you-sync-files-and-folders
@ -1895,8 +1976,9 @@ final class SyncEngine
foreach (DirEntry entry; entries) {
uploadNewItems(entry.name);
}
} catch (std.file.FileException e) {
log.error("ERROR: ", e.msg);
} catch (FileException e) {
// display the error message
displayFileSystemErrorMessage(e.msg);
return;
}
} else {
@ -1910,9 +1992,13 @@ final class SyncEngine
}
Item item;
if (!itemdb.selectByPath(path, defaultDriveId, item)) {
// item is not in the database, upload new file
uploadNewFile(path);
remainingFreeSpace = (remainingFreeSpace - fileSize);
log.vlog("Remaining free space: ", remainingFreeSpace);
if (!uploadFailed) {
// upload did not fail
remainingFreeSpace = (remainingFreeSpace - fileSize);
log.vlog("Remaining free space: ", remainingFreeSpace);
}
}
} else {
// Not enough free space
@ -1925,6 +2011,7 @@ final class SyncEngine
}
}
// create new directory on OneDrive
private void uploadCreateDir(const(string) path)
{
log.vlog("OneDrive Client requested to create remote path: ", path);
@ -2058,8 +2145,12 @@ final class SyncEngine
}
}
// upload a new file to OneDrive
private void uploadNewFile(string path)
{
// Reset upload failure - OneDrive or filesystem issue (reading data)
uploadFailed = false;
Item parent;
// Check the database for the parent
//enforce(itemdb.selectByPath(dirName(path), defaultDriveId, parent), "The parent item is not in the local database");
@ -2089,8 +2180,9 @@ final class SyncEngine
fileDetailsFromOneDrive = onedrive.getPathDetails(path);
} catch (OneDriveException e) {
if (e.httpStatusCode == 401) {
// OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - no error message logged
log.error("ERROR: OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error");
// OneDrive returned a 'HTTP/1.1 401 Unauthorized Error'
writeln("Skipping item - OneDrive returned a 'HTTP 401 - Unauthorized' when attempting to query if file exists");
log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error");
return;
}
@ -2101,7 +2193,7 @@ final class SyncEngine
writeln("Skipping item - excluded by skip_size config: ", path, " (", thisFileSize/2^^20," MB)");
return;
}
write("Uploading new file ", path, " ...");
write("Uploading new file ", path, " ... ");
JSONValue response;
if (!dryRun) {
@ -2113,6 +2205,16 @@ final class SyncEngine
response = onedrive.simpleUpload(path, parent.driveId, parent.id, baseName(path));
} catch (OneDriveException e) {
// error uploading file
// display what the error is
writeln("skipped.");
displayOneDriveErrorMessage(e.msg);
uploadFailed = true;
return;
} catch (FileException e) {
// display the error message
writeln("skipped.");
displayFileSystemErrorMessage(e.msg);
uploadFailed = true;
return;
}
} else {
@ -2126,6 +2228,13 @@ final class SyncEngine
try {
response = onedrive.simpleUpload(path, parent.driveId, parent.id, baseName(path));
} catch (OneDriveException e) {
if (e.httpStatusCode == 401) {
// OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded
writeln("skipped.");
log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error");
uploadFailed = true;
return;
}
if (e.httpStatusCode == 504) {
// HTTP request returned status code 504 (Gateway Timeout)
// Try upload as a session
@ -2133,10 +2242,25 @@ final class SyncEngine
response = session.upload(path, parent.driveId, parent.id, baseName(path));
} catch (OneDriveException e) {
// error uploading file
// display what the error is
writeln("skipped.");
displayOneDriveErrorMessage(e.msg);
uploadFailed = true;
return;
}
} else {
// display what the error is
writeln("skipped.");
displayOneDriveErrorMessage(e.msg);
uploadFailed = true;
return;
}
else throw e;
} catch (FileException e) {
// display the error message
writeln("skipped.");
displayFileSystemErrorMessage(e.msg);
uploadFailed = true;
return;
}
} else {
// File larger than threshold - use a session to upload
@ -2144,11 +2268,24 @@ final class SyncEngine
try {
response = session.upload(path, parent.driveId, parent.id, baseName(path));
} catch (OneDriveException e) {
// error uploading file
log.vlog("Upload failed with OneDriveException: ", e.msg);
return;
if (e.httpStatusCode == 401) {
// OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded
writeln("skipped.");
log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error");
uploadFailed = true;
return;
} else {
// display what the error is
writeln("skipped.");
displayOneDriveErrorMessage(e.msg);
uploadFailed = true;
return;
}
} catch (FileException e) {
log.vlog("Upload failed with File Exception: ", e.msg);
// display the error message
writeln("skipped.");
displayFileSystemErrorMessage(e.msg);
uploadFailed = true;
return;
}
}
@ -2158,11 +2295,24 @@ final class SyncEngine
try {
response = session.upload(path, parent.driveId, parent.id, baseName(path));
} catch (OneDriveException e) {
// error uploading file
log.vlog("Upload failed with OneDriveException: ", e.msg);
return;
if (e.httpStatusCode == 401) {
// OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded
writeln("skipped.");
log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error");
uploadFailed = true;
return;
} else {
// display what the error is
writeln("skipped.");
displayOneDriveErrorMessage(e.msg);
uploadFailed = true;
return;
}
} catch (FileException e) {
log.vlog("Upload failed with File Exception: ", e.msg);
// display the error message
writeln("skipped.");
displayFileSystemErrorMessage(e.msg);
uploadFailed = true;
return;
}
}
@ -2170,9 +2320,10 @@ final class SyncEngine
// response from OneDrive has to be a valid JSON object
if (response.type() == JSONType.object){
// upload done without error
writeln("done.");
// Log action to log file
log.fileOnly("Uploading new file ", path, " ... done.");
writeln(" done.");
// The file was uploaded, or a 4xx / 5xx error was generated
if ("size" in response){
// The response JSON contains size, high likelihood valid response returned
@ -2241,7 +2392,7 @@ final class SyncEngine
}
} else {
// we are --dry-run - simulate the file upload
writeln(" done.");
writeln("done.");
response = createFakeResponse(path);
// Log action to log file
log.fileOnly("Uploading new file ", path, " ... done.");
@ -2277,47 +2428,140 @@ final class SyncEngine
if (localFileModifiedTime > remoteFileModifiedTime){
// local file is newer
log.vlog("Requested file to upload is newer than existing file on OneDrive");
write("Uploading modified file ", path, " ...");
write("Uploading modified file ", path, " ... ");
JSONValue response;
if (!dryRun) {
if (accountType == "personal"){
// OneDrive Personal account upload handling
if (getSize(path) <= thresholdFileSize) {
response = onedrive.simpleUpload(path, parent.driveId, parent.id, baseName(path));
writeln(" done.");
if (thisFileSize <= thresholdFileSize) {
try {
response = onedrive.simpleUpload(path, parent.driveId, parent.id, baseName(path));
writeln("done.");
} catch (OneDriveException e) {
if (e.httpStatusCode == 401) {
// OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded
writeln("skipped.");
log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error");
uploadFailed = true;
return;
}
if (e.httpStatusCode == 504) {
// HTTP request returned status code 504 (Gateway Timeout)
// Try upload as a session
try {
response = session.upload(path, parent.driveId, parent.id, baseName(path));
writeln("done.");
} catch (OneDriveException e) {
// error uploading file
// display what the error is
writeln("skipped.");
displayOneDriveErrorMessage(e.msg);
uploadFailed = true;
return;
}
} else {
// display what the error is
writeln("skipped.");
displayOneDriveErrorMessage(e.msg);
uploadFailed = true;
return;
}
} catch (FileException e) {
// display the error message
writeln("skipped.");
displayFileSystemErrorMessage(e.msg);
uploadFailed = true;
return;
}
} else {
// File larger than threshold - use a session to upload
writeln("");
response = session.upload(path, parent.driveId, parent.id, baseName(path));
writeln(" done.");
}
string id = response["id"].str;
string cTag;
// Is there a valid cTag in the response?
if ("cTag" in response) {
// use the cTag instead of the eTag because Onedrive may update the metadata of files AFTER they have been uploaded
cTag = response["cTag"].str;
} else {
// Is there an eTag in the response?
if ("eTag" in response) {
// use the eTag from the response as there was no cTag
cTag = response["eTag"].str;
} else {
// no tag available - set to nothing
cTag = "";
try {
response = session.upload(path, parent.driveId, parent.id, baseName(path));
writeln("done.");
} catch (OneDriveException e) {
if (e.httpStatusCode == 401) {
// OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded
writeln("skipped.");
log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error");
uploadFailed = true;
return;
} else {
// display what the error is
writeln("skipped.");
displayOneDriveErrorMessage(e.msg);
uploadFailed = true;
return;
}
} catch (FileException e) {
// display the error message
writeln("skipped.");
displayFileSystemErrorMessage(e.msg);
uploadFailed = true;
return;
}
}
SysTime mtime = timeLastModified(path).toUTC();
uploadLastModifiedTime(parent.driveId, id, cTag, mtime);
// response from OneDrive has to be a valid JSON object
if (response.type() == JSONType.object){
// response is a valid JSON object
string id = response["id"].str;
string cTag;
// Is there a valid cTag in the response?
if ("cTag" in response) {
// use the cTag instead of the eTag because Onedrive may update the metadata of files AFTER they have been uploaded
cTag = response["cTag"].str;
} else {
// Is there an eTag in the response?
if ("eTag" in response) {
// use the eTag from the response as there was no cTag
cTag = response["eTag"].str;
} else {
// no tag available - set to nothing
cTag = "";
}
}
if (exists(path)) {
SysTime mtime = timeLastModified(path).toUTC();
uploadLastModifiedTime(parent.driveId, id, cTag, mtime);
} else {
// will be removed in different event!
log.log("File disappeared after upload: ", path);
}
}
} else {
// OneDrive Business account modified file upload handling
if (accountType == "business"){
// OneDrive Business Account - always use a session to upload
writeln("");
// session upload
response = session.upload(path, parent.driveId, parent.id, baseName(path), fileDetailsFromOneDrive["eTag"].str);
writeln(" done.");
try {
response = session.upload(path, parent.driveId, parent.id, baseName(path), fileDetailsFromOneDrive["eTag"].str);
} catch (OneDriveException e) {
if (e.httpStatusCode == 401) {
// OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded
writeln("skipped.");
log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error");
uploadFailed = true;
return;
} else {
// display what the error is
writeln("skipped.");
displayOneDriveErrorMessage(e.msg);
uploadFailed = true;
return;
}
} catch (FileException e) {
// display the error message
writeln("skipped.");
displayFileSystemErrorMessage(e.msg);
uploadFailed = true;
return;
}
// upload complete
writeln("done.");
saveItem(response);
}
@ -2329,17 +2573,61 @@ final class SyncEngine
// We also cant use a session to upload the file, we have to use simpleUploadReplace
if (getSize(path) <= thresholdFileSize) {
// Upload file via simpleUploadReplace as below threshhold size
response = onedrive.simpleUploadReplace(path, fileDetailsFromOneDrive["parentReference"]["driveId"].str, fileDetailsFromOneDrive["id"].str, fileDetailsFromOneDrive["eTag"].str);
// Upload file via simpleUploadReplace as below threshold size
try {
response = onedrive.simpleUploadReplace(path, fileDetailsFromOneDrive["parentReference"]["driveId"].str, fileDetailsFromOneDrive["id"].str, fileDetailsFromOneDrive["eTag"].str);
} catch (OneDriveException e) {
if (e.httpStatusCode == 401) {
// OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded
writeln("skipped.");
log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error");
uploadFailed = true;
return;
} else {
// display what the error is
writeln("skipped.");
displayOneDriveErrorMessage(e.msg);
uploadFailed = true;
return;
}
} catch (FileException e) {
// display the error message
writeln("skipped.");
displayFileSystemErrorMessage(e.msg);
uploadFailed = true;
return;
}
} else {
// Have to upload via a session, however we have to delete the file first otherwise this will generate a 404 error post session upload
// Remove the existing file
onedrive.deleteById(fileDetailsFromOneDrive["parentReference"]["driveId"].str, fileDetailsFromOneDrive["id"].str, fileDetailsFromOneDrive["eTag"].str);
// Upload as a session, as a new file
writeln("");
response = session.upload(path, parent.driveId, parent.id, baseName(path));
try {
response = session.upload(path, parent.driveId, parent.id, baseName(path));
} catch (OneDriveException e) {
if (e.httpStatusCode == 401) {
// OneDrive returned a 'HTTP/1.1 401 Unauthorized Error' - file failed to be uploaded
writeln("skipped.");
log.vlog("OneDrive returned a 'HTTP 401 - Unauthorized' - gracefully handling error");
uploadFailed = true;
return;
} else {
// display what the error is
writeln("skipped.");
displayOneDriveErrorMessage(e.msg);
uploadFailed = true;
return;
}
} catch (FileException e) {
// display the error message
writeln("skipped.");
displayFileSystemErrorMessage(e.msg);
uploadFailed = true;
return;
}
}
writeln(" done.");
writeln("done.");
saveItem(response);
// Due to https://github.com/OneDrive/onedrive-api-docs/issues/935 Microsoft modifies all PDF, MS Office & HTML files with added XML content. It is a 'feature' of SharePoint.
// So - now the 'local' and 'remote' file is technically DIFFERENT ... thanks Microsoft .. NO way to disable this stupidity
@ -2358,7 +2646,7 @@ final class SyncEngine
}
} else {
// we are --dry-run - simulate the file upload
writeln(" done.");
writeln("done.");
response = createFakeResponse(path);
// Log action to log file
log.fileOnly("Uploading modified file ", path, " ... done.");
@ -2368,7 +2656,6 @@ final class SyncEngine
// Log action to log file
log.fileOnly("Uploading modified file ", path, " ... done.");
} else {
// Save the details of the file that we got from OneDrive
// --dry-run safe
@ -2397,6 +2684,7 @@ final class SyncEngine
}
}
// delete an item on OneDrive
private void uploadDeleteItem(Item item, string path)
{
log.log("Deleting item from OneDrive: ", path);
@ -2436,12 +2724,8 @@ final class SyncEngine
}
} else {
// Not a 403 response & OneDrive Business Account / O365 Shared Folder / Library
log.log("\n\nOneDrive returned an error with the following message:\n");
auto errorArray = splitLines(e.msg);
log.log("Error Message: ", errorArray[0]);
// extract 'message' as the reason
JSONValue errorMessage = parseJSON(replace(e.msg, errorArray[0], ""));
log.log("Error Reason: ", errorMessage["error"]["message"].str);
// display what the error is
displayOneDriveErrorMessage(e.msg);
return;
}
}
@ -2456,6 +2740,7 @@ final class SyncEngine
}
}
// update the item's last modified time
private void uploadLastModifiedTime(const(char)[] driveId, const(char)[] id, const(char)[] eTag, SysTime mtime)
{
JSONValue data = [
@ -2481,6 +2766,7 @@ final class SyncEngine
saveItem(response);
}
// save item details into database
private void saveItem(JSONValue jsonItem)
{
// jsonItem has to be a valid object
@ -2504,6 +2790,23 @@ final class SyncEngine
}
}
// Parse and display error message received from OneDrive
private void displayOneDriveErrorMessage(string message) {
log.error("ERROR: OneDrive returned an error with the following message:");
auto errorArray = splitLines(message);
log.error(" Error Message: ", errorArray[0]);
// extract 'message' as the reason
JSONValue errorMessage = parseJSON(replace(message, errorArray[0], ""));
log.error(" Error Reason: ", errorMessage["error"]["message"].str);
}
// Parse and display error message received from the local file system
private void displayFileSystemErrorMessage(string message) {
log.error("ERROR: The local file system returned an error with the following message:");
auto errorArray = splitLines(message);
log.error(" Error Message: ", errorArray[0]);
}
// https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_move
// This function is only called in monitor mode when an move event is coming from
// inotify and we try to move the item.
@ -2551,6 +2854,7 @@ final class SyncEngine
}
}
// delete an item by it's path
void deleteByPath(string path)
{
Item item;
@ -2564,8 +2868,12 @@ final class SyncEngine
try {
uploadDeleteItem(item, path);
} catch (OneDriveException e) {
if (e.httpStatusCode == 404) log.log(e.msg);
else throw e;
if (e.httpStatusCode == 404) {
log.log(e.msg);
} else {
// display what the error is
displayOneDriveErrorMessage(e.msg);
}
}
}
@ -2622,11 +2930,7 @@ final class SyncEngine
return;
} else {
// display what the error is
auto errorArray = splitLines(e.msg);
log.error("Error Message: ", errorArray[0]);
// extract 'message' as the reason
JSONValue errorMessage = parseJSON(replace(e.msg, errorArray[0], ""));
log.error("Error Reason: ", errorMessage["error"]["message"].str);
displayOneDriveErrorMessage(e.msg);
return;
}
}
@ -2647,11 +2951,8 @@ final class SyncEngine
siteDriveQuery = onedrive.o365SiteDrives(site_id);
} catch (OneDriveException e) {
log.error("ERROR: Query of OneDrive for Office Site ID failed");
auto errorArray = splitLines(e.msg);
log.error("Error Message: ", errorArray[0]);
// extract 'message' as the reason
JSONValue errorMessage = parseJSON(replace(e.msg, errorArray[0], ""));
log.error("Error Reason: ", errorMessage["error"]["message"].str);
// display what the error is
displayOneDriveErrorMessage(e.msg);
return;
}
@ -2700,7 +3001,9 @@ final class SyncEngine
try {
fileDetails = onedrive.getFileDetails(item.driveId, item.id);
} catch (OneDriveException e) {
log.error("ERROR: Query of OneDrive for file details failed");
// display what the error is
displayOneDriveErrorMessage(e.msg);
return;
}
if ((fileDetails.type() == JSONType.object) && ("webUrl" in fileDetails)) {