From 62ccf1f902100febfb1be02b67e84a6e4938ebbf Mon Sep 17 00:00:00 2001 From: Alexander Tkachev Date: Thu, 26 May 2016 17:56:13 +0600 Subject: CLOUD: Add RequestInfo struct ConnectionManager upgrade: it now contains a special struct for each request, so you can access request status and data by request id. --- backends/cloud/downloadrequest.cpp | 17 ++++++++- backends/cloud/downloadrequest.h | 1 + .../cloud/dropbox/dropboxlistdirectoryrequest.cpp | 34 ++++++++++++++---- .../cloud/dropbox/dropboxlistdirectoryrequest.h | 6 ++++ backends/networking/curl/connectionmanager.cpp | 41 +++++++++++++++++----- backends/networking/curl/connectionmanager.h | 24 +++++++++++-- backends/networking/curl/curljsonrequest.cpp | 2 ++ backends/networking/curl/curlrequest.cpp | 9 ++++- backends/networking/curl/curlrequest.h | 2 +- backends/networking/curl/request.h | 2 ++ 10 files changed, 117 insertions(+), 21 deletions(-) diff --git a/backends/cloud/downloadrequest.cpp b/backends/cloud/downloadrequest.cpp index e86b6552e9..a96c298fe8 100644 --- a/backends/cloud/downloadrequest.cpp +++ b/backends/cloud/downloadrequest.cpp @@ -21,6 +21,7 @@ */ #include "backends/cloud/downloadrequest.h" +#include "backends/networking/curl/connectionmanager.h" #include "common/debug.h" #include "common/textconsole.h" @@ -32,16 +33,19 @@ DownloadRequest::DownloadRequest(Storage::BoolCallback callback, Networking::Net bool DownloadRequest::handle() { if (!_remoteFileStream) { warning("DownloadRequest: no stream to read"); + ConnMan.getRequestInfo(_id).state = Networking::FINISHED; return true; } if (!_localFile) { warning("DownloadRequest: no file to write"); + ConnMan.getRequestInfo(_id).state = Networking::FINISHED; return true; } if (!_localFile->isOpen()) { warning("DownloadRequest: failed to open file to write"); + ConnMan.getRequestInfo(_id).state = Networking::FINISHED; return true; } @@ -52,7 +56,8 @@ bool DownloadRequest::handle() { if (readBytes != 0) if (_localFile->write(buf, readBytes) != readBytes) { warning("DownloadRequest: unable to write all received bytes into output file"); - if (_boolCallback) (*_boolCallback)(false); + ConnMan.getRequestInfo(_id).state = Networking::FINISHED; + if (_boolCallback) (*_boolCallback)(false); return true; } @@ -62,6 +67,7 @@ bool DownloadRequest::handle() { //TODO: do something about it actually } + ConnMan.getRequestInfo(_id).state = Networking::FINISHED; if (_boolCallback) (*_boolCallback)(_remoteFileStream->httpResponseCode() == 200); _localFile->close(); //yes, I know it's closed automatically in ~DumpFile() @@ -71,4 +77,13 @@ bool DownloadRequest::handle() { return false; } +void DownloadRequest::restart() { + //this request doesn't know anything about the _remoteFileStream it's reading + //thus, it can't restart it + warning("DownloadRequest: cannot be restarted"); + ConnMan.getRequestInfo(_id).state = Networking::FINISHED; + if (_boolCallback) (*_boolCallback)(false); + //TODO: fix that +} + } //end of namespace Cloud diff --git a/backends/cloud/downloadrequest.h b/backends/cloud/downloadrequest.h index b135b15f23..c1564100c2 100644 --- a/backends/cloud/downloadrequest.h +++ b/backends/cloud/downloadrequest.h @@ -40,6 +40,7 @@ public: virtual ~DownloadRequest() { delete _localFile; } virtual bool handle(); + virtual void restart(); }; } //end of namespace Cloud diff --git a/backends/cloud/dropbox/dropboxlistdirectoryrequest.cpp b/backends/cloud/dropbox/dropboxlistdirectoryrequest.cpp index 5e5957b12c..3dada884a0 100644 --- a/backends/cloud/dropbox/dropboxlistdirectoryrequest.cpp +++ b/backends/cloud/dropbox/dropboxlistdirectoryrequest.cpp @@ -30,24 +30,33 @@ namespace Cloud { namespace Dropbox { DropboxListDirectoryRequest::DropboxListDirectoryRequest(Common::String token, Common::String path, Storage::FileArrayCallback cb, bool recursive): - Networking::Request(0), _filesCallback(cb), _token(token), _complete(false) { - Common::BaseCallback<> *innerCallback = new Common::Callback(this, &DropboxListDirectoryRequest::responseCallback);//new Common::GlobalFunctionCallback(printJson); //okay + Networking::Request(0), _requestedPath(path), _requestedRecursive(recursive), _filesCallback(cb), + _token(token), _complete(false), _requestId(-1) { + startupWork(); +} + +void DropboxListDirectoryRequest::startupWork() { + _files.clear(); + _complete = false; + + Common::BaseCallback<> *innerCallback = new Common::Callback(this, &DropboxListDirectoryRequest::responseCallback); Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, "https://api.dropboxapi.com/2/files/list_folder"); request->addHeader("Authorization: Bearer " + _token); request->addHeader("Content-Type: application/json"); Common::JSONObject jsonRequestParameters; - jsonRequestParameters.setVal("path", new Common::JSONValue(path)); - jsonRequestParameters.setVal("recursive", new Common::JSONValue(recursive)); + jsonRequestParameters.setVal("path", new Common::JSONValue(_requestedPath)); + jsonRequestParameters.setVal("recursive", new Common::JSONValue(_requestedRecursive)); jsonRequestParameters.setVal("include_media_info", new Common::JSONValue(false)); jsonRequestParameters.setVal("include_deleted", new Common::JSONValue(false)); Common::JSONValue value(jsonRequestParameters); request->addPostField(Common::JSON::stringify(&value)); - ConnMan.addRequest(request); + _requestId = ConnMan.addRequest(request); } + void DropboxListDirectoryRequest::responseCallback(void *jsonPtr) { Common::JSONValue *json = (Common::JSONValue *)jsonPtr; if (json) { @@ -103,13 +112,24 @@ void DropboxListDirectoryRequest::responseCallback(void *jsonPtr) { } bool DropboxListDirectoryRequest::handle() { - if (_complete && _filesCallback) { - (*_filesCallback)(_files); + if (_complete && _filesCallback) { + ConnMan.getRequestInfo(_id).state = Networking::FINISHED; + if (_filesCallback) (*_filesCallback)(_files); } return _complete; } +void DropboxListDirectoryRequest::restart() { + if (_requestId != -1) { + Networking::RequestInfo &info = ConnMan.getRequestInfo(_requestId); + //TODO: I'm really not sure some CurlRequest would handle this (it must stop corresponding CURL transfer) + info.state = Networking::FINISHED; //may be CANCELED or INTERRUPTED or something? + _requestId = -1; + } + + startupWork(); +} } //end of namespace Dropbox } //end of namespace Cloud diff --git a/backends/cloud/dropbox/dropboxlistdirectoryrequest.h b/backends/cloud/dropbox/dropboxlistdirectoryrequest.h index 0c10512782..36070a2a32 100644 --- a/backends/cloud/dropbox/dropboxlistdirectoryrequest.h +++ b/backends/cloud/dropbox/dropboxlistdirectoryrequest.h @@ -31,18 +31,24 @@ namespace Cloud { namespace Dropbox { class DropboxListDirectoryRequest: public Networking::Request { + Common::String _requestedPath; + bool _requestedRecursive; + Storage::FileArrayCallback _filesCallback; Common::String _token; bool _complete; Common::Array _files; + int32 _requestId; void responseCallback(void *jsonPtr); + void startupWork(); public: DropboxListDirectoryRequest(Common::String token, Common::String path, Storage::FileArrayCallback cb, bool recursive = false); virtual ~DropboxListDirectoryRequest() { delete _filesCallback; } virtual bool handle(); + virtual void restart(); }; } //end of namespace Dropbox diff --git a/backends/networking/curl/connectionmanager.cpp b/backends/networking/curl/connectionmanager.cpp index 8428bd25f0..b448d8e514 100644 --- a/backends/networking/curl/connectionmanager.cpp +++ b/backends/networking/curl/connectionmanager.cpp @@ -50,12 +50,16 @@ void ConnectionManager::registerEasyHandle(CURL *easy) { int32 ConnectionManager::addRequest(Request *request) { int32 newId = _nextId++; - _requests[newId] = request; + _requests[newId] = RequestInfo(newId, request); request->setId(newId); if (!_timerStarted) startTimer(); return newId; } +RequestInfo &ConnectionManager::getRequestInfo(int32 id) { + return _requests[id]; +} + //private goes here: void connectionsThread(void *ignored) { @@ -87,15 +91,34 @@ void ConnectionManager::handle() { void ConnectionManager::interateRequests() { //call handle() of all running requests (so they can do their work) debug("handling %d request(s)", _requests.size()); - for (Common::HashMap::iterator i = _requests.begin(); i != _requests.end();) { - Request *request = i->_value; - if (request && request->handle()) { - delete request; - //_requests.erase(i); - _requests[i->_key] = 0; - ++i; //that's temporary - } else ++i; + Common::Array idsToRemove; + for (Common::HashMap::iterator i = _requests.begin(); i != _requests.end(); ++i) { + RequestInfo &info = _requests[i->_key]; + + switch(info.state) { + case FINISHED: + delete info.request; + info.request = 0; + idsToRemove.push_back(info.id); + break; + + case PROCESSING: + info.request->handle(); + break; + + case RETRY: + if (info.retryInSeconds > 0) --info.retryInSeconds; + else { + info.state = PROCESSING; + info.request->restart(); + } + + default: + ; //nothing to do + } } + for (uint32 i = 0; i < idsToRemove.size(); ++i) + _requests.erase(idsToRemove[i]); if (_requests.empty()) stopTimer(); } diff --git a/backends/networking/curl/connectionmanager.h b/backends/networking/curl/connectionmanager.h index 9651a0166a..9ae52b3eeb 100644 --- a/backends/networking/curl/connectionmanager.h +++ b/backends/networking/curl/connectionmanager.h @@ -36,12 +36,30 @@ namespace Networking { class NetworkReadStream; +enum RequestState { + PROCESSING, + PAUSED, + RETRY, + FINISHED +}; + +struct RequestInfo { + int32 id; + Request *request; + RequestState state; + void *data; + uint32 retryInSeconds; + + RequestInfo() : id(-1), request(0), state(FINISHED), data(0), retryInSeconds(0) {} + RequestInfo(int32 rqId, Request *rq) : id(rqId), request(rq), state(PROCESSING), data(0), retryInSeconds(0) {} +}; + class ConnectionManager : public Common::Singleton { friend void connectionsThread(void *); //calls handle() CURLM *_multi; bool _timerStarted; - Common::HashMap _requests; + Common::HashMap _requests; int32 _nextId; void startTimer(int interval = 1000000); //1 second is the default interval @@ -70,7 +88,9 @@ public: * * @return generated Request's id, which might be used to get its status */ - int32 addRequest(Request *request); + int32 addRequest(Request *request); + + RequestInfo &getRequestInfo(int32 id); }; /** Shortcut for accessing the connection manager. */ diff --git a/backends/networking/curl/curljsonrequest.cpp b/backends/networking/curl/curljsonrequest.cpp index 0366e3b403..21c0a0f644 100644 --- a/backends/networking/curl/curljsonrequest.cpp +++ b/backends/networking/curl/curljsonrequest.cpp @@ -23,6 +23,7 @@ #define FORBIDDEN_SYMBOL_ALLOW_ALL #include "backends/networking/curl/curljsonrequest.h" +#include "backends/networking/curl/connectionmanager.h" #include "backends/networking/curl/networkreadstream.h" #include "common/debug.h" #include "common/json.h" @@ -68,6 +69,7 @@ bool CurlJsonRequest::handle() { if (_stream->httpResponseCode() != 200) warning("HTTP response code is not 200 OK (it's %ld)", _stream->httpResponseCode()); + ConnMan.getRequestInfo(_id).state = Networking::FINISHED; if (_callback) { char *contents = getPreparedContents(); if (_stream->httpResponseCode() != 200) diff --git a/backends/networking/curl/curlrequest.cpp b/backends/networking/curl/curlrequest.cpp index e13adaca59..e1c8f2b18c 100644 --- a/backends/networking/curl/curlrequest.cpp +++ b/backends/networking/curl/curlrequest.cpp @@ -42,13 +42,20 @@ bool CurlRequest::handle() { if (_stream && _stream->eos()) { if (_stream->httpResponseCode() != 200) - warning("HTTP response code is not 200 OK (it's %ld)", _stream->httpResponseCode()); + warning("HTTP response code is not 200 OK (it's %ld)", _stream->httpResponseCode()); + ConnMan.getRequestInfo(_id).state = Networking::FINISHED; return true; } return false; } +void CurlRequest::restart() { + if (_stream) delete _stream; + _stream = 0; + //with no stream available next handle() will create another one +} + 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 22f50be418..ec1a9e33c6 100644 --- a/backends/networking/curl/curlrequest.h +++ b/backends/networking/curl/curlrequest.h @@ -44,9 +44,9 @@ public: virtual ~CurlRequest(); virtual bool handle(); + virtual void restart(); void addHeader(Common::String header); - void addPostField(Common::String header); /** Start this Request with ConnMan. Returns its ReadStream. */ diff --git a/backends/networking/curl/request.h b/backends/networking/curl/request.h index 0265d3e2f3..136f007920 100644 --- a/backends/networking/curl/request.h +++ b/backends/networking/curl/request.h @@ -51,6 +51,8 @@ public: virtual bool handle() = 0; + virtual void restart() = 0; + void setId(int32 id) { _id = id; } }; -- cgit v1.2.3