CLOUD: Fix OneDriveStorage API interaction

Something changed and old API endpoint "api.onedrive.com" now does not
work. The other one, "graph.microsoft.com", does, but there were some
other changes in JSON it returns. These changes are also in this commit.
This commit is contained in:
Alexander Tkachev 2019-07-16 14:12:45 +07:00 committed by Matan Bareket
parent e8669f693c
commit edbea10c2e
7 changed files with 61 additions and 14 deletions

View File

@ -31,7 +31,7 @@
namespace Cloud {
namespace OneDrive {
#define ONEDRIVE_API_SPECIAL_APPROOT "https://api.onedrive.com/v1.0/drive/special/approot"
#define ONEDRIVE_API_SPECIAL_APPROOT "https://graph.microsoft.com/v1.0/drive/special/approot"
OneDriveCreateDirectoryRequest::OneDriveCreateDirectoryRequest(OneDriveStorage *storage, Common::String path, Storage::BoolCallback cb, Networking::ErrorCallback ecb):
Networking::Request(nullptr, ecb), _storage(storage), _path(path), _boolCallback(cb),

View File

@ -31,7 +31,8 @@
namespace Cloud {
namespace OneDrive {
#define ONEDRIVE_API_SPECIAL_APPROOT_CHILDREN "https://api.onedrive.com/v1.0/drive/special/approot:/%s:/children"
#define ONEDRIVE_API_SPECIAL_APPROOT_CHILDREN "https://graph.microsoft.com/v1.0/drive/special/approot:/%s:/children"
#define ONEDRIVE_API_SPECIAL_APPROOT_CHILDREN_ROOT_ITSELF "https://graph.microsoft.com/v1.0/drive/special/approot/children"
OneDriveListDirectoryRequest::OneDriveListDirectoryRequest(OneDriveStorage *storage, Common::String path, Storage::ListDirectoryCallback cb, Networking::ErrorCallback ecb, bool recursive):
Networking::Request(nullptr, ecb),
@ -77,6 +78,7 @@ void OneDriveListDirectoryRequest::listNextDirectory() {
Common::String dir = _currentDirectory;
dir.deleteLastChar();
Common::String url = Common::String::format(ONEDRIVE_API_SPECIAL_APPROOT_CHILDREN, ConnMan.urlEncode(dir).c_str());
if (dir == "") url = Common::String(ONEDRIVE_API_SPECIAL_APPROOT_CHILDREN_ROOT_ITSELF);
makeRequest(url);
}
@ -84,7 +86,7 @@ void OneDriveListDirectoryRequest::makeRequest(Common::String url) {
Networking::JsonCallback callback = new Common::Callback<OneDriveListDirectoryRequest, Networking::JsonResponse>(this, &OneDriveListDirectoryRequest::listedDirectoryCallback);
Networking::ErrorCallback failureCallback = new Common::Callback<OneDriveListDirectoryRequest, Networking::ErrorResponse>(this, &OneDriveListDirectoryRequest::listedDirectoryErrorCallback);
Networking::CurlJsonRequest *request = new OneDriveTokenRefresher(_storage, callback, failureCallback, url.c_str());
request->addHeader("Authorization: Bearer " + _storage->accessToken());
request->addHeader("Authorization: bearer " + _storage->accessToken());
_workingRequest = ConnMan.addRequest(request);
}

View File

@ -39,8 +39,8 @@
namespace Cloud {
namespace OneDrive {
#define ONEDRIVE_API_SPECIAL_APPROOT_ID "https://api.onedrive.com/v1.0/drive/special/approot:/"
#define ONEDRIVE_API_SPECIAL_APPROOT "https://api.onedrive.com/v1.0/drive/special/approot"
#define ONEDRIVE_API_SPECIAL_APPROOT_ID "https://graph.microsoft.com/v1.0/drive/special/approot:/"
#define ONEDRIVE_API_SPECIAL_APPROOT "https://graph.microsoft.com/v1.0/drive/special/approot"
OneDriveStorage::OneDriveStorage(Common::String token, Common::String refreshToken):
BaseStorage(token, refreshToken) {}
@ -136,7 +136,7 @@ void OneDriveStorage::fileInfoCallback(Networking::NetworkReadStreamCallback out
}
Common::JSONObject result = response.value->asObject();
if (!Networking::CurlJsonRequest::jsonContainsString(result, "@content.downloadUrl", "OneDriveStorage::fileInfoCallback")) {
if (!Networking::CurlJsonRequest::jsonContainsString(result, "@microsoft.graph.downloadUrl", "OneDriveStorage::fileInfoCallback")) {
warning("OneDriveStorage: downloadUrl not found in passed JSON");
debug(9, "%s", response.value->stringify().c_str());
if (outerCallback)
@ -146,7 +146,7 @@ void OneDriveStorage::fileInfoCallback(Networking::NetworkReadStreamCallback out
return;
}
const char *url = result.getVal("@content.downloadUrl")->asString().c_str();
const char *url = result.getVal("@microsoft.graph.downloadUrl")->asString().c_str();
if (outerCallback)
(*outerCallback)(Networking::NetworkReadStreamResponse(
response.request,
@ -158,28 +158,33 @@ void OneDriveStorage::fileInfoCallback(Networking::NetworkReadStreamCallback out
}
Networking::Request *OneDriveStorage::listDirectory(Common::String path, ListDirectoryCallback callback, Networking::ErrorCallback errorCallback, bool recursive) {
debug(9, "OneDrive: `ls \"%s\"`", path.c_str());
return addRequest(new OneDriveListDirectoryRequest(this, path, callback, errorCallback, recursive));
}
Networking::Request *OneDriveStorage::upload(Common::String path, Common::SeekableReadStream *contents, UploadCallback callback, Networking::ErrorCallback errorCallback) {
debug(9, "OneDrive: `upload \"%s\"`", path.c_str());
return addRequest(new OneDriveUploadRequest(this, path, contents, callback, errorCallback));
}
Networking::Request *OneDriveStorage::streamFileById(Common::String path, Networking::NetworkReadStreamCallback outerCallback, Networking::ErrorCallback errorCallback) {
debug(9, "OneDrive: `download \"%s\"`", path.c_str());
Common::String url = ONEDRIVE_API_SPECIAL_APPROOT_ID + ConnMan.urlEncode(path);
Networking::JsonCallback innerCallback = new Common::CallbackBridge<OneDriveStorage, Networking::NetworkReadStreamResponse, Networking::JsonResponse>(this, &OneDriveStorage::fileInfoCallback, outerCallback);
Networking::CurlJsonRequest *request = new OneDriveTokenRefresher(this, innerCallback, errorCallback, url.c_str());
request->addHeader("Authorization: Bearer " + _token);
request->addHeader("Authorization: bearer " + _token);
return addRequest(request);
}
Networking::Request *OneDriveStorage::createDirectory(Common::String path, BoolCallback callback, Networking::ErrorCallback errorCallback) {
debug(9, "OneDrive: `mkdir \"%s\"`", path.c_str());
if (!errorCallback)
errorCallback = getErrorPrintingCallback();
return addRequest(new OneDriveCreateDirectoryRequest(this, path, callback, errorCallback));
}
Networking::Request *OneDriveStorage::info(StorageInfoCallback callback, Networking::ErrorCallback errorCallback) {
debug(9, "OneDrive: `info`");
Networking::JsonCallback innerCallback = new Common::CallbackBridge<OneDriveStorage, StorageInfoResponse, Networking::JsonResponse>(this, &OneDriveStorage::infoInnerCallback, callback);
Networking::CurlJsonRequest *request = new OneDriveTokenRefresher(this, innerCallback, errorCallback, ONEDRIVE_API_SPECIAL_APPROOT);
request->addHeader("Authorization: bearer " + _token);

View File

@ -94,7 +94,7 @@ void OneDriveTokenRefresher::finishJson(Common::JSONValue *json) {
irrecoverable = false;
}
if (code == "unauthenticated")
if (code == "unauthenticated" || code == "InvalidAuthenticationToken")
irrecoverable = false;
if (irrecoverable) {
@ -114,6 +114,30 @@ void OneDriveTokenRefresher::finishJson(Common::JSONValue *json) {
CurlJsonRequest::finishJson(json);
}
void OneDriveTokenRefresher::finishError(Networking::ErrorResponse error) {
bool irrecoverable = error.interrupted || error.failed;
if (error.failed) {
Common::JSONValue *value = Common::JSON::parse(error.response.c_str());
//somehow OneDrive returns JSON with '.' in unexpected places, try fixing it
if (!value) {
Common::String fixedResponse = error.response;
for (uint32 i = 0; i < fixedResponse.size(); ++i) {
if (fixedResponse[i] == '.')
fixedResponse.replace(i, 1, " ");
}
value = Common::JSON::parse(fixedResponse.c_str());
}
if (value) {
finishJson(value);
return;
}
}
Request::finishError(error); //call closest base class's method
}
void OneDriveTokenRefresher::setHeaders(Common::Array<Common::String> &headers) {
_headers = headers;
curl_slist_free_all(_headersList);

View File

@ -38,6 +38,7 @@ class OneDriveTokenRefresher: public Networking::CurlJsonRequest {
void tokenRefreshed(Storage::BoolResponse response);
virtual void finishJson(Common::JSONValue *json);
virtual void finishError(Networking::ErrorResponse error);
public:
OneDriveTokenRefresher(OneDriveStorage *parent, Networking::JsonCallback callback, Networking::ErrorCallback ecb, const char *url);
virtual ~OneDriveTokenRefresher();

View File

@ -33,8 +33,8 @@
namespace Cloud {
namespace OneDrive {
#define ONEDRIVE_API_SPECIAL_APPROOT_UPLOAD "https://api.onedrive.com/v1.0/drive/special/approot:/%s:/upload.createSession"
#define ONEDRIVE_API_SPECIAL_APPROOT_CONTENT "https://api.onedrive.com/v1.0/drive/special/approot:/%s:/content"
#define ONEDRIVE_API_SPECIAL_APPROOT_UPLOAD "https://graph.microsoft.com/v1.0/drive/special/approot:/%s:/upload.createSession"
#define ONEDRIVE_API_SPECIAL_APPROOT_CONTENT "https://graph.microsoft.com/v1.0/drive/special/approot:/%s:/content"
OneDriveUploadRequest::OneDriveUploadRequest(OneDriveStorage *storage, Common::String path, Common::SeekableReadStream *contents, Storage::UploadCallback callback, Networking::ErrorCallback ecb):
Networking::Request(nullptr, ecb), _storage(storage), _savePath(path), _contentsStream(contents), _uploadCallback(callback),

View File

@ -126,11 +126,11 @@ void SavesSyncRequest::directoryListedCallback(Storage::ListDirectoryResponse re
_filesToUpload.push_back(i->_key);
}
debug(9, "\nSavesSyncRequest: download files:");
debug(9, (_filesToDownload.size() > 0 ? "\nSavesSyncRequest: download files:" : "\nSavesSyncRequest: nothing to download"));
for (uint32 i = 0; i < _filesToDownload.size(); ++i) {
debug(9, "%s", _filesToDownload[i].name().c_str());
}
debug(9, "\nSavesSyncRequest: upload files:");
debug(9, (_filesToUpload.size() > 0 ? "\nSavesSyncRequest: upload files:" : "\nSavesSyncRequest: nothing to upload"));
for (uint32 i = 0; i < _filesToUpload.size(); ++i) {
debug(9, "%s", _filesToUpload[i].c_str());
}
@ -145,9 +145,22 @@ void SavesSyncRequest::directoryListedErrorCallback(Networking::ErrorResponse er
if (_ignoreCallback)
return;
if (error.failed) debug(9, "%s", error.response.c_str());
bool irrecoverable = error.interrupted || error.failed;
if (error.failed) {
Common::JSONValue *value = Common::JSON::parse(error.response.c_str());
// somehow OneDrive returns JSON with '.' in unexpected places, try fixing it
if (!value) {
Common::String fixedResponse = error.response;
for (uint32 i = 0; i < fixedResponse.size(); ++i) {
if (fixedResponse[i] == '.')
fixedResponse.replace(i, 1, " ");
}
value = Common::JSON::parse(fixedResponse.c_str());
}
if (value) {
if (value->isObject()) {
Common::JSONObject object = value->asObject();
@ -174,11 +187,13 @@ void SavesSyncRequest::directoryListedErrorCallback(Networking::ErrorResponse er
delete value;
}
//Google Drive and Box-related ScummVM-based error
//Google Drive, Box and OneDrive-related ScummVM-based error
if (error.response.contains("subdirectory not found")) {
irrecoverable = false; //base "/ScummVM/" folder not found
} else if (error.response.contains("no such file found in its parent directory")) {
irrecoverable = false; //"Saves" folder within "/ScummVM/" not found
} else if (error.response.contains("itemNotFound") && error.response.contains("Item does not exist")) {
irrecoverable = false; //"saves" folder within application folder is not found
}
}