diff options
author | Alexander Tkachev | 2016-05-26 21:40:01 +0600 |
---|---|---|
committer | Alexander Tkachev | 2016-08-24 16:07:55 +0600 |
commit | 8f6bcdf55da97db98384c2a8cb9dcdf34232ac35 (patch) | |
tree | a1ec4f773c2891cf432f05af2461ca161959a017 /backends | |
parent | b246c17850687e7b15b644b761fbfe835ffc1c32 (diff) | |
download | scummvm-rg350-8f6bcdf55da97db98384c2a8cb9dcdf34232ac35.tar.gz scummvm-rg350-8f6bcdf55da97db98384c2a8cb9dcdf34232ac35.tar.bz2 scummvm-rg350-8f6bcdf55da97db98384c2a8cb9dcdf34232ac35.zip |
CLOUD: Add OneDriveTokenRefresher
OneDriveTokenRefresher is a CurlJsonRequest replacement for
OneDriveStorage methods. It behaves very similarly, but checks received
JSON before passing it to user. If it contains "error" key, it attempts
to refresh the token through OneDriveStorage, and then restarts the
original request, so user won't notice that there ever was an error.
Diffstat (limited to 'backends')
-rw-r--r-- | backends/cloud/onedrive/onedrivestorage.cpp | 16 | ||||
-rw-r--r-- | backends/cloud/onedrive/onedrivestorage.h | 15 | ||||
-rw-r--r-- | backends/cloud/onedrive/onedrivetokenrefresher.cpp | 124 | ||||
-rw-r--r-- | backends/cloud/onedrive/onedrivetokenrefresher.h | 61 | ||||
-rw-r--r-- | backends/module.mk | 3 | ||||
-rw-r--r-- | backends/networking/curl/connectionmanager.cpp | 2 | ||||
-rw-r--r-- | backends/networking/curl/curljsonrequest.cpp | 9 | ||||
-rw-r--r-- | backends/networking/curl/curljsonrequest.h | 3 | ||||
-rw-r--r-- | backends/networking/curl/curlrequest.cpp | 7 | ||||
-rw-r--r-- | backends/networking/curl/curlrequest.h | 8 |
10 files changed, 222 insertions, 26 deletions
diff --git a/backends/cloud/onedrive/onedrivestorage.cpp b/backends/cloud/onedrive/onedrivestorage.cpp index 833ba8e558..6f91cadd37 100644 --- a/backends/cloud/onedrive/onedrivestorage.cpp +++ b/backends/cloud/onedrive/onedrivestorage.cpp @@ -31,6 +31,7 @@ #include <common/file.h> #include "common/system.h" #include "common/cloudmanager.h" +#include "onedrivetokenrefresher.h" namespace Cloud { namespace OneDrive { @@ -113,10 +114,6 @@ void OneDriveStorage::saveConfig(Common::String keyPrefix) { ConfMan.set(keyPrefix + "refresh_token", _refreshToken, "cloud"); } -void OneDriveStorage::printJsonTokenReceived(RequestBoolPair pair) { - if (pair.value) syncSaves(0); //try again -} - void OneDriveStorage::printJson(Networking::RequestJsonPair pair) { Common::JSONValue *json = pair.value; if (!json) { @@ -124,15 +121,6 @@ void OneDriveStorage::printJson(Networking::RequestJsonPair pair) { return; } - Common::JSONObject result = json->asObject(); - if (result.contains("error")) { - //Common::JSONObject error = result.getVal("error")->asObject(); - debug("bad token, trying again..."); - getAccessToken(new Common::Callback<OneDriveStorage, RequestBoolPair>(this, &OneDriveStorage::printJsonTokenReceived)); - delete json; - return; - } - debug("%s", json->stringify().c_str()); delete json; } @@ -140,7 +128,7 @@ void OneDriveStorage::printJson(Networking::RequestJsonPair pair) { int32 OneDriveStorage::syncSaves(BoolCallback callback) { //this is not the real syncSaves() implementation Networking::JsonCallback innerCallback = new Common::Callback<OneDriveStorage, Networking::RequestJsonPair>(this, &OneDriveStorage::printJson); - Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, "https://api.onedrive.com/v1.0/drives/"); + Networking::CurlJsonRequest *request = new OneDriveTokenRefresher(this, innerCallback, "https://api.onedrive.com/v1.0/drives/"); request->addHeader("Authorization: bearer " + _token); return ConnMan.addRequest(request); } diff --git a/backends/cloud/onedrive/onedrivestorage.h b/backends/cloud/onedrive/onedrivestorage.h index 1cb7017d64..e120691a08 100644 --- a/backends/cloud/onedrive/onedrivestorage.h +++ b/backends/cloud/onedrive/onedrivestorage.h @@ -44,12 +44,6 @@ class OneDriveStorage: public Cloud::Storage { */ OneDriveStorage(Common::String code); - /** - * Gets new access_token. If <code> passed is "", refresh_token is used. - * Use "" in order to refresh token and pass a callback, so you could - * continue your work when new token is available. - */ - void getAccessToken(BoolCallback callback, Common::String code = ""); void tokenRefreshed(BoolCallback callback, Networking::RequestJsonPair pair); void codeFlowComplete(RequestBoolPair pair); @@ -122,6 +116,15 @@ public: * Show message with OneDrive auth instructions. (Temporary) */ static void authThroughConsole(); + + /** + * Gets new access_token. If <code> passed is "", refresh_token is used. + * Use "" in order to refresh token and pass a callback, so you could + * continue your work when new token is available. + */ + void getAccessToken(BoolCallback callback, Common::String code = ""); + + Common::String accessToken() { return _token; } }; } //end of namespace OneDrive diff --git a/backends/cloud/onedrive/onedrivetokenrefresher.cpp b/backends/cloud/onedrive/onedrivetokenrefresher.cpp new file mode 100644 index 0000000000..5e72717740 --- /dev/null +++ b/backends/cloud/onedrive/onedrivetokenrefresher.cpp @@ -0,0 +1,124 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "backends/cloud/onedrive/onedrivetokenrefresher.h" +#include "backends/cloud/onedrive/onedrivestorage.h" +#include "backends/networking/curl/connectionmanager.h" +#include "backends/networking/curl/curljsonrequest.h" +#include "common/config-manager.h" +#include "common/debug.h" +#include "common/json.h" +#include <curl/curl.h> + +namespace Cloud { +namespace OneDrive { + +OneDriveTokenRefresher::OneDriveTokenRefresher(OneDriveStorage *parent, Networking::JsonCallback callback, const char *url): + CurlJsonRequest(0, url), + _parentStorage(parent), + _innerRequest( + new CurlJsonRequest( + new Common::Callback<OneDriveTokenRefresher, Networking::RequestJsonPair>(this, &OneDriveTokenRefresher::innerRequestCallback), + url + ) + ), _jsonCallback(callback), _retryId(-1), _started(false) {} + +OneDriveTokenRefresher::~OneDriveTokenRefresher() {} + +void OneDriveTokenRefresher::innerRequestCallback(Networking::RequestJsonPair pair) { + if (!pair.value) { + //notify user of failure + warning("OneDriveTokenRefresher: got NULL instead of JSON"); + ConnMan.getRequestInfo(_id).state = Networking::FINISHED; + if (_jsonCallback) (*_jsonCallback)(Networking::RequestJsonPair(_id, 0)); + return; + } + + Common::JSONObject result = pair.value->asObject(); + if (result.contains("error")) { + //new token needed => request token & then retry original request + ConnMan.getRequestInfo(pair.id).state = Networking::PAUSED; + _retryId = pair.id; + delete pair.value; + _parentStorage->getAccessToken(new Common::Callback<OneDriveTokenRefresher, Storage::RequestBoolPair>(this, &OneDriveTokenRefresher::tokenRefreshed)); + return; + } + + //notify user of success + ConnMan.getRequestInfo(_id).state = Networking::FINISHED; + if (_jsonCallback) (*_jsonCallback)(Networking::RequestJsonPair(_id, pair.value)); +} + +void OneDriveTokenRefresher::tokenRefreshed(Storage::RequestBoolPair pair) { + if (!pair.value) { + //failed to refresh token, notify user with NULL in original callback + warning("OneDriveTokenRefresher: failed to refresh token"); + ConnMan.getRequestInfo(_id).state = Networking::FINISHED; + if (_jsonCallback) (*_jsonCallback)(Networking::RequestJsonPair(_id, 0)); + return; + } + + //successfully received refreshed token, can restart the original request now + Networking::RequestInfo &info = ConnMan.getRequestInfo(_retryId); + info.state = Networking::RETRY; + info.retryInSeconds = 1; + + //update headers: first change header with token, then pass those to request + for (uint32 i = 0; i < _headers.size(); ++i) { + if (_headers[i].contains("Authorization: bearer ")) { + _headers[i] = "Authorization: bearer " + _parentStorage->accessToken(); + } + } + CurlJsonRequest *retryRequest = (CurlJsonRequest *)info.request; + if (retryRequest) retryRequest->setHeaders(_headers); +} + +void OneDriveTokenRefresher::handle() { + if (!_started) { + for (uint32 i = 0; i < _headers.size(); ++i) + _innerRequest->addHeader(_headers[i]); + _started = true; + ConnMan.addRequest(_innerRequest); + } +} + +void OneDriveTokenRefresher::restart() { + //can't restart as all headers were passed to _innerRequest which is probably dead now + warning("OneDriveTokenRefresher: cannot be restarted"); + ConnMan.getRequestInfo(_id).state = Networking::FINISHED; + if (_jsonCallback) (*_jsonCallback)(Networking::RequestJsonPair(_id, 0)); +} + +Networking::NetworkReadStream *OneDriveTokenRefresher::execute() { + if (!_started) { + for (uint32 i = 0; i < _headers.size(); ++i) + _innerRequest->addHeader(_headers[i]); + _started = true; + } else { + warning("OneDriveTokenRefresher: inner Request is already started"); + } + return _innerRequest->execute(); +} + +} //end of namespace OneDrive +} //end of namespace Cloud diff --git a/backends/cloud/onedrive/onedrivetokenrefresher.h b/backends/cloud/onedrive/onedrivetokenrefresher.h new file mode 100644 index 0000000000..976851282e --- /dev/null +++ b/backends/cloud/onedrive/onedrivetokenrefresher.h @@ -0,0 +1,61 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#ifndef BACKENDS_CLOUD_ONEDRIVE_ONEDRIVETOKENREFRESHER_H +#define BACKENDS_CLOUD_ONEDRIVE_ONEDRIVETOKENREFRESHER_H + +#include "backends/cloud/storage.h" +#include "common/callback.h" +#include "backends/networking/curl/curljsonrequest.h" + +namespace Cloud { +namespace OneDrive { + +class OneDriveStorage; + +class OneDriveTokenRefresher: public Networking::CurlJsonRequest { + OneDriveStorage *_parentStorage; + Common::Array<Common::String> _headers; + Networking::CurlJsonRequest *_innerRequest; + Networking::JsonCallback _jsonCallback; + int32 _retryId; + bool _started; + + void innerRequestCallback(Networking::RequestJsonPair pair); + void tokenRefreshed(Storage::RequestBoolPair pair); +public: + OneDriveTokenRefresher(OneDriveStorage *parent, Networking::JsonCallback callback, const char *url); + virtual ~OneDriveTokenRefresher(); + + virtual void handle(); + virtual void restart(); + + virtual void setHeaders(Common::Array<Common::String> &headers) { _headers = headers; } + virtual void addHeader(Common::String header) { _headers.push_back(header); } + virtual void addPostField(Common::String field) { _innerRequest->addPostField(field); } + virtual Networking::NetworkReadStream *execute(); +}; + +} //end of namespace OneDrive +} //end of namespace Cloud + +#endif diff --git a/backends/module.mk b/backends/module.mk index c8842ca32b..5ec34190e9 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -27,7 +27,8 @@ MODULE_OBJS += \ cloud/downloadrequest.o \ cloud/dropbox/dropboxstorage.o \ cloud/dropbox/dropboxlistdirectoryrequest.o \ - cloud/onedrive/onedrivestorage.o + cloud/onedrive/onedrivestorage.o \ + cloud/onedrive/onedrivetokenrefresher.o endif ifdef USE_LIBCURL diff --git a/backends/networking/curl/connectionmanager.cpp b/backends/networking/curl/connectionmanager.cpp index b448d8e514..77a46ec518 100644 --- a/backends/networking/curl/connectionmanager.cpp +++ b/backends/networking/curl/connectionmanager.cpp @@ -76,6 +76,7 @@ void ConnectionManager::startTimer(int interval) { } void ConnectionManager::stopTimer() { + debug("timer stopped"); Common::TimerManager *manager = g_system->getTimerManager(); manager->removeTimerProc(connectionsThread); _timerStarted = false; @@ -111,6 +112,7 @@ void ConnectionManager::interateRequests() { else { info.state = PROCESSING; info.request->restart(); + debug("request restarted"); } default: diff --git a/backends/networking/curl/curljsonrequest.cpp b/backends/networking/curl/curljsonrequest.cpp index a323b34ed2..1231f9e7e8 100644 --- a/backends/networking/curl/curljsonrequest.cpp +++ b/backends/networking/curl/curljsonrequest.cpp @@ -74,11 +74,18 @@ void CurlJsonRequest::handle() { char *contents = getPreparedContents(); if (_stream->httpResponseCode() != 200) debug("%s", contents); - Common::JSONValue *json = Common::JSON::parse(contents); + Common::JSONValue *json = Common::JSON::parse(contents); (*_jsonCallback)(RequestJsonPair(_id, json)); //potential memory leak, free it in your callbacks! } } } } +void CurlJsonRequest::restart() { + if (_stream) delete _stream; + _stream = 0; + _contentsStream = Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES); + //with no stream available next handle() will create another one +} + } //end of namespace Networking diff --git a/backends/networking/curl/curljsonrequest.h b/backends/networking/curl/curljsonrequest.h index 75d4a6df81..af19ec3596 100644 --- a/backends/networking/curl/curljsonrequest.h +++ b/backends/networking/curl/curljsonrequest.h @@ -45,7 +45,8 @@ public: CurlJsonRequest(JsonCallback cb, const char *url); virtual ~CurlJsonRequest(); - virtual void handle(); + virtual void handle(); + virtual void restart(); }; } //end of namespace Networking diff --git a/backends/networking/curl/curlrequest.cpp b/backends/networking/curl/curlrequest.cpp index e30b7ce018..1b42ac5931 100644 --- a/backends/networking/curl/curlrequest.cpp +++ b/backends/networking/curl/curlrequest.cpp @@ -53,6 +53,13 @@ void CurlRequest::restart() { //with no stream available next handle() will create another one } +void CurlRequest::setHeaders(Common::Array<Common::String> &headers) { + curl_slist_free_all(_headersList); + _headersList = 0; + for (uint32 i = 0; i < headers.size(); ++i) + addHeader(headers[i]); +} + void CurlRequest::addHeader(Common::String header) { _headersList = curl_slist_append(_headersList, header.c_str()); } diff --git a/backends/networking/curl/curlrequest.h b/backends/networking/curl/curlrequest.h index 1a644e4369..c624194142 100644 --- a/backends/networking/curl/curlrequest.h +++ b/backends/networking/curl/curlrequest.h @@ -25,6 +25,7 @@ #include "backends/networking/curl/request.h" #include "common/str.h" +#include <common/array.h> struct curl_slist; @@ -46,11 +47,12 @@ public: virtual void handle(); virtual void restart(); - void addHeader(Common::String header); - void addPostField(Common::String header); + virtual void setHeaders(Common::Array<Common::String> &headers); + virtual void addHeader(Common::String header); + virtual void addPostField(Common::String field); /** Start this Request with ConnMan. Returns its ReadStream. */ - NetworkReadStream *execute(); + virtual NetworkReadStream *execute(); }; } //end of namespace Networking |