Update with working state

* Update with working state
This commit is contained in:
abraunegg 2024-03-31 09:03:58 +11:00
parent a3050bca54
commit c1a619f82f
4 changed files with 67 additions and 39 deletions

View file

@ -201,6 +201,7 @@ class CurlEngine {
bool keepAlive;
ulong dnsTimeout;
CurlResponse response;
File uploadFile;
this() {
http = HTTP();
@ -210,6 +211,8 @@ class CurlEngine {
~this() {
object.destroy(http);
object.destroy(response);
if (uploadFile.isOpen())
uploadFile.close();
}
void initialise(ulong dnsTimeout, ulong connectTimeout, ulong dataTimeout, ulong operationTimeout, int maxRedirects, bool httpsDebug, string userAgent, bool httpProtocol, ulong userRateLimit, ulong protocolVersion, bool keepAlive=true) {
@ -337,10 +340,25 @@ class CurlEngine {
}
}
void setFile(File* file, ulong offsetSize) {
void setFile(string filepath, string contentRange, ulong offset, ulong offsetSize) {
setResponseHolder(null);
// open file as read-only in binary mode
uploadFile = File(filepath, "rb");
if (contentRange.empty) {
offsetSize = uploadFile.size();
} else {
addRequestHeader("Content-Range", contentRange);
uploadFile.seek(offset);
}
// Setup progress bar to display
http.onProgress = delegate int(size_t dltotal, size_t dlnow, size_t ultotal, size_t ulnow) {
return 0;
};
addRequestHeader("Content-Type", "application/octet-stream");
http.onSend = data => file.rawRead(data).length;
http.onSend = data => uploadFile.rawRead(data).length;
http.contentLength = offsetSize;
}
@ -362,9 +380,6 @@ class CurlEngine {
CurlResponse download(string originalFilename, string downloadFilename) {
setResponseHolder(null);
// Threshold for displaying download bar
long thresholdFileSize = 4 * 2^^20; // 4 MiB
// open downloadFilename as write in binary mode
auto file = File(downloadFilename, "wb");
@ -403,6 +418,12 @@ class CurlEngine {
};
http.contentLength = 0;
response = null;
// close file if open
if (uploadFile.isOpen()){
// close open file
uploadFile.close();
}
}
void shutdown() {

View file

@ -208,13 +208,38 @@ final class ItemDatabase {
if (e.msg == "database is locked") {
addLogEntry();
addLogEntry("ERROR: The 'onedrive' application is already running - please check system process list for active application instances");
addLogEntry(" - Use 'sudo ps aufxw | grep onedrive' to potentially determine acive running process", ["verbose"]);
addLogEntry(" - Use 'sudo ps aufxw | grep onedrive' to potentially determine acive running process");
addLogEntry();
} else {
// A different error .. detail the message, detail the actual SQLite Error Code to assist with troubleshooting
addLogEntry();
addLogEntry("ERROR: An internal database error occurred: " ~ e.msg ~ " (SQLite Error Code: " ~ to!string(e.errorCode) ~ ")");
addLogEntry();
// Give the user some additional information and pointers on this error
// The below list is based on user issue / discussion reports since 2018
switch (e.errorCode) {
case 7: // SQLITE_NOMEM
addLogEntry("The operation could not be completed due to insufficient memory. Please close unnecessary applications to free up memory and try again.");
break;
case 10: // SQLITE_IOERR
addLogEntry("A disk I/O error occurred. This could be due to issues with the storage medium (e.g., disk full, hardware failure, filesystem corruption). Please check your disk's health using a disk utility tool, ensure there is enough free space, and check the filesystem for errors.");
break;
case 11: // SQLITE_CORRUPT
addLogEntry("The database file appears to be corrupt. This could be due to incomplete or failed writes, hardware issues, or unexpected interruptions during database operations. Please perform a --resync operation.");
break;
case 14: // SQLITE_CANTOPEN
addLogEntry("The database file could not be opened. Please check that the database file exists, has the correct permissions, and is not being blocked by another process or security software.");
break;
case 26: // SQLITE_NOTADB
addLogEntry("The file attempted to be opened does not appear to be a valid SQLite database, or it may have been corrupted to a point where it's no longer recognizable. Please check your application configuration directory and/or perform a --resync operation.");
break;
default:
addLogEntry("An unexpected error occurred. Please consult the application documentation or support to resolve this issue.");
break;
}
// Blank line before exit
addLogEntry();
}
return;
}

View file

@ -392,12 +392,10 @@ class OneDriveApi {
string authFilesString = appConfig.getValueString("auth_files");
string authResponseString = appConfig.getValueString("auth_response");
// Is authResponseString not empty
if (!authResponseString.empty) {
// read the response from authResponseString
response = cast(char[]) authResponseString;
} else if (authFilesString != "") {
// authResponseString empty .. is authFilesString not empty
string[] authFiles = authFilesString.split(":");
string authUrl = authFiles[0];
string responseUrl = authFiles[1];
@ -422,7 +420,6 @@ class OneDriveApi {
exit(-1);
}
// Add logging that we are waiting for auth elements to be available
addLogEntry("Client requires authentication before proceeding. Waiting for --auth-files elements to be available.");
while (!exists(responseUrl)) {
@ -529,7 +526,6 @@ class OneDriveApi {
// Return all the items that are shared with the user
// https://docs.microsoft.com/en-us/graph/api/drive-sharedwithme
JSONValue getSharedWithMe() {
checkAccessTokenExpired();
return get(sharedWithMeUrl);
}
@ -683,7 +679,6 @@ class OneDriveApi {
}
JSONValue createSubscription(string notificationUrl, SysTime expirationDateTime) {
checkAccessTokenExpired();
string driveId = appConfig.getValueString("drive_id");
string url = subscriptionUrl;
@ -772,7 +767,6 @@ class OneDriveApi {
// Private OneDrive API Functions
private void addIncludeFeatureRequestHeader(string[string]* headers) {
addLogEntry("Adding 'Include-Feature=AddToOneDrive' API request header as 'sync_business_shared_items' config option is enabled", ["debug"]);
(*headers)["Prefer"] = "Include-Feature=AddToOneDrive";
}
@ -919,10 +913,11 @@ class OneDriveApi {
}
private void performDelete(const(char)[] url, string[string] requestHeaders=null, string callingFunction=__FUNCTION__, int lineno=__LINE__) {
bool validateJSONResponse = false;
oneDriveErrorHandlerWrapper((CurlResponse response) {
connect(HTTP.Method.del, url, false, response, requestHeaders);
return curlEngine.execute();
}, callingFunction, lineno);
}, validateJSONResponse, callingFunction, lineno);
}
private void downloadFile(const(char)[] url, string filename, long fileSize, string callingFunction=__FUNCTION__, int lineno=__LINE__) {
@ -1067,55 +1062,42 @@ class OneDriveApi {
}
private JSONValue get(string url, bool skipToken = false, string[string] requestHeaders=null, string callingFunction=__FUNCTION__, int lineno=__LINE__) {
bool validateJSONResponse = true;
return oneDriveErrorHandlerWrapper((CurlResponse response) {
connect(HTTP.Method.get, url, skipToken, response, requestHeaders);
return curlEngine.execute();
}, callingFunction, lineno);
}, validateJSONResponse, callingFunction, lineno);
}
private JSONValue patch(const(char)[] url, const(char)[] patchData, string[string] requestHeaders=null, const(char)[] contentType = "application/json", string callingFunction=__FUNCTION__, int lineno=__LINE__) {
bool validateJSONResponse = true;
return oneDriveErrorHandlerWrapper((CurlResponse response) {
connect(HTTP.Method.patch, url, false, response, requestHeaders);
curlEngine.setContent(contentType, patchData);
return curlEngine.execute();
}, callingFunction, lineno);
}, validateJSONResponse, callingFunction, lineno);
}
private JSONValue post(const(char)[] url, const(char)[] postData, bool skipToken = false, const(char)[] contentType = "application/json", string callingFunction=__FUNCTION__, int lineno=__LINE__) {
bool validateJSONResponse = true;
return oneDriveErrorHandlerWrapper((CurlResponse response) {
connect(HTTP.Method.post, url, skipToken, response);
curlEngine.setContent(contentType, postData);
return curlEngine.execute();
}, callingFunction, lineno);
}, validateJSONResponse, callingFunction, lineno);
}
private JSONValue put(const(char)[] url, string filepath, bool skipToken=false, string contentRange=null, ulong offset=0, ulong offsetSize=0, string callingFunction=__FUNCTION__, int lineno=__LINE__) {
bool validateJSONResponse = true;
return oneDriveErrorHandlerWrapper((CurlResponse response) {
string[string] requestHeaders;
// open file as read-only in binary mode
auto file = File(filepath, "rb");
if (!contentRange.empty)
file.seek(offset);
// function scopes
scope(exit) {
// close file if open
if (file.isOpen()){
// close open file
file.close();
}
}
if (!contentRange.empty)
requestHeaders["Content-Range"] = contentRange;
else
offsetSize = file.size;
connect(HTTP.Method.put, url, skipToken, response, requestHeaders);
curlEngine.setFile(&file, offsetSize);
connect(HTTP.Method.put, url, skipToken, response);
curlEngine.setFile(filepath, contentRange, offset, offsetSize);
return curlEngine.execute();
}, callingFunction, lineno);
}, validateJSONResponse, callingFunction, lineno);
}
// Wrapper function for all requests to OneDrive API
// throws a OneDriveException
// throws OneDriveException
private JSONValue oneDriveErrorHandlerWrapper(CurlResponse delegate(CurlResponse response) executer, bool validateJSONResponse, string callingFunction, int lineno) {
int maxRetryCount = 10;
int retryAttempts = 0;

View file

@ -4847,11 +4847,11 @@ class SyncEngine {
onlinePathData = foundDirectoryJSONItem;
} else {
// No 'search item matches found' - raise a 404 so that the exception handling will take over to create the folder
throw new OneDriveException(404, "Name not found via search", null);
throw new OneDriveException(404, "Name not found via search");
}
} else {
// No 'search item matches found' - raise a 404 so that the exception handling will take over to create the folder
throw new OneDriveException(404, "Name not found via search", null);
throw new OneDriveException(404, "Name not found via search");
}
}
} catch (OneDriveException exception) {