diff options
author | Alexander Tkachev | 2016-05-18 15:21:09 +0600 |
---|---|---|
committer | Alexander Tkachev | 2016-08-24 16:07:55 +0600 |
commit | 0a947618fb1faa023df03d355e9749905424dd58 (patch) | |
tree | db663626a23c333da1f9279cd6f92e8ce9c6e610 /backends/networking/curl | |
parent | e743a65636a674def45e955cb7a5632aead2a033 (diff) | |
download | scummvm-rg350-0a947618fb1faa023df03d355e9749905424dd58.tar.gz scummvm-rg350-0a947618fb1faa023df03d355e9749905424dd58.tar.bz2 scummvm-rg350-0a947618fb1faa023df03d355e9749905424dd58.zip |
CLOUD: Make ConnectionManager singleton
With ConnectionManager singleton one can start their Requests without
creating Storage instance. Moreover, Storage instance should contain
cloud API, not Requests-related handling and timer starting methods.
Thus, these methods were moved into ConnectionManager itself.
Diffstat (limited to 'backends/networking/curl')
-rw-r--r-- | backends/networking/curl/connectionmanager.cpp | 63 | ||||
-rw-r--r-- | backends/networking/curl/connectionmanager.h | 40 | ||||
-rw-r--r-- | backends/networking/curl/curljsonrequest.cpp | 5 | ||||
-rw-r--r-- | backends/networking/curl/curljsonrequest.h | 6 | ||||
-rw-r--r-- | backends/networking/curl/networkreadstream.cpp | 2 | ||||
-rw-r--r-- | backends/networking/curl/networkreadstream.h | 2 | ||||
-rw-r--r-- | backends/networking/curl/request.h | 54 |
7 files changed, 153 insertions, 19 deletions
diff --git a/backends/networking/curl/connectionmanager.cpp b/backends/networking/curl/connectionmanager.cpp index d34eab23e8..31e99f989c 100644 --- a/backends/networking/curl/connectionmanager.cpp +++ b/backends/networking/curl/connectionmanager.cpp @@ -25,11 +25,16 @@ #include "backends/networking/curl/connectionmanager.h" #include "backends/networking/curl/networkreadstream.h" #include "common/debug.h" +#include "common/system.h" +#include "common/timer.h" #include <curl/curl.h> +using Common::Singleton; + +DECLARE_SINGLETON(Networking::ConnectionManager); namespace Networking { -ConnectionManager::ConnectionManager(): _multi(0) { +ConnectionManager::ConnectionManager(): _multi(0), _timerStarted(false) { curl_global_init(CURL_GLOBAL_ALL); _multi = curl_multi_init(); } @@ -39,13 +44,57 @@ ConnectionManager::~ConnectionManager() { curl_global_cleanup(); } -NetworkReadStream *ConnectionManager::makeRequest(const char *url, curl_slist *headersList, Common::String postFields) { - NetworkReadStream *stream = new NetworkReadStream(url, headersList, postFields); - curl_multi_add_handle(_multi, stream->getEasyHandle()); - return stream; +void ConnectionManager::registerEasyHandle(CURL *easy) { + curl_multi_add_handle(_multi, easy); +} + +void ConnectionManager::addRequest(Request *request) { + _requests.push_back(request); + if (!_timerStarted) startTimer(); +} + +//private goes here: + +void connectionsThread(void *ignored) { + ConnMan.handle(); +} + +void ConnectionManager::startTimer(int interval) { + Common::TimerManager *manager = g_system->getTimerManager(); + if (manager->installTimerProc(connectionsThread, interval, 0, "Networking::ConnectionManager's Timer")) { + _timerStarted = true; + } else { + warning("Failed to install Networking::ConnectionManager's timer"); + } +} + +void ConnectionManager::stopTimer() { + Common::TimerManager *manager = g_system->getTimerManager(); + manager->removeTimerProc(connectionsThread); + _timerStarted = false; } void ConnectionManager::handle() { + //TODO: lock mutex here (in case another handle() would be called before this one ends) + interateRequests(); + processTransfers(); + //TODO: unlock mutex here +} + +void ConnectionManager::interateRequests() { + //call handle() of all running requests (so they can do their work) + debug("handler's here"); + for (Common::Array<Request *>::iterator i = _requests.begin(); i != _requests.end();) { + if ((*i)->handle()) { + delete (*i); + _requests.erase(i); + } else ++i; + } + if (_requests.empty()) stopTimer(); +} + +void ConnectionManager::processTransfers() { + //check libcurl's transfers and notify requests of messages from queue (transfer completion or failure) int transfersRunning; curl_multi_perform(_multi, &transfersRunning); @@ -59,9 +108,9 @@ void ConnectionManager::handle() { if (stream) stream->finished(); if (curlMsg->msg == CURLMSG_DONE) { - debug("ConnectionManager: SUCCESS (%d - %s)", curlMsg->data.result, curl_easy_strerror(curlMsg->data.result)); + debug("ConnectionManager: SUCCESS (%d - %s)", curlMsg->data.result, curl_easy_strerror(curlMsg->data.result)); } else { - debug("ConnectionManager: FAILURE (CURLMsg (%d))", curlMsg->msg); + debug("ConnectionManager: FAILURE (CURLMsg (%d))", curlMsg->msg); } curl_multi_remove_handle(_multi, easyHandle); diff --git a/backends/networking/curl/connectionmanager.h b/backends/networking/curl/connectionmanager.h index b83de6191a..ed726441c4 100644 --- a/backends/networking/curl/connectionmanager.h +++ b/backends/networking/curl/connectionmanager.h @@ -23,8 +23,12 @@ #ifndef BACKENDS_NETWORKING_CURL_CONNECTIONMANAGER_H #define BACKENDS_NETWORKING_CURL_CONNECTIONMANAGER_H +#include "backends/networking/curl/request.h" #include "common/str.h" +#include "common/singleton.h" +#include "common/array.h" +typedef void CURL; typedef void CURLM; struct curl_slist; @@ -32,17 +36,43 @@ namespace Networking { class NetworkReadStream; -class ConnectionManager { - CURLM *_multi; +class ConnectionManager : public Common::Singleton<ConnectionManager> { + friend void connectionsThread(void *); //calls handle() + + CURLM *_multi; + bool _timerStarted; + Common::Array<Request *> _requests; + + void startTimer(int interval = 1000000); //1 second is the default interval + void stopTimer(); + void handle(); + void interateRequests(); + void processTransfers(); public: ConnectionManager(); virtual ~ConnectionManager(); - NetworkReadStream *makeRequest(const char *url, curl_slist *headersList, Common::String postFields); - void handle(); + /** + * All libcurl transfers are going through this ConnectionManager. + * So, if you want to start any libcurl transfer, you must create + * an easy handle and register it using this method. + */ + void registerEasyHandle(CURL *easy); + + /** + * Use this method to add new Request into manager's queue. + * Manager will periodically call handle() method of these + * Requests until they return true. + * + * @note This method starts the timer if it's not started yet. + */ + void addRequest(Request *request); }; -} //end of namespace Cloud +/** Shortcut for accessing the connection manager. */ +#define ConnMan Networking::ConnectionManager::instance() + +} //end of namespace Networking #endif diff --git a/backends/networking/curl/curljsonrequest.cpp b/backends/networking/curl/curljsonrequest.cpp index 0c6363467a..59bc830692 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" @@ -56,8 +57,8 @@ char *CurlJsonRequest::getPreparedContents() { return (char *)result; } -bool CurlJsonRequest::handle(ConnectionManager &manager) { - if (!_stream) _stream = manager.makeRequest(_url, _headersList, _postFields); +bool CurlJsonRequest::handle() { + if (!_stream) _stream = new NetworkReadStream(_url, _headersList, _postFields); if (_stream) { const int kBufSize = 16*1024; diff --git a/backends/networking/curl/curljsonrequest.h b/backends/networking/curl/curljsonrequest.h index 17df9693f2..cbf3f6dd56 100644 --- a/backends/networking/curl/curljsonrequest.h +++ b/backends/networking/curl/curljsonrequest.h @@ -23,7 +23,7 @@ #ifndef BACKENDS_NETWORKING_CURL_CURLJSONREQUEST_H #define BACKENDS_NETWORKING_CURL_CURLJSONREQUEST_H -#include "backends/cloud/request.h" +#include "backends/networking/curl/request.h" #include "common/memstream.h" struct curl_slist; @@ -32,7 +32,7 @@ namespace Networking { class NetworkReadStream; -class CurlJsonRequest : public Cloud::Request { +class CurlJsonRequest : public Request { const char *_url; NetworkReadStream *_stream; curl_slist *_headersList; @@ -46,7 +46,7 @@ public: CurlJsonRequest(Callback cb, const char *url); virtual ~CurlJsonRequest(); - virtual bool handle(ConnectionManager &manager); + virtual bool handle(); void addHeader(Common::String header); diff --git a/backends/networking/curl/networkreadstream.cpp b/backends/networking/curl/networkreadstream.cpp index f2af4fd50c..8fd39d6884 100644 --- a/backends/networking/curl/networkreadstream.cpp +++ b/backends/networking/curl/networkreadstream.cpp @@ -23,6 +23,7 @@ #define FORBIDDEN_SYMBOL_ALLOW_ALL #include "backends/networking/curl/networkreadstream.h" +#include "backends/networking/curl/connectionmanager.h" #include "common/debug.h" #include <curl/curl.h> @@ -47,6 +48,7 @@ NetworkReadStream::NetworkReadStream(const char *url, curl_slist *headersList, C curl_easy_setopt(_easy, CURLOPT_HTTPHEADER, headersList); curl_easy_setopt(_easy, CURLOPT_POSTFIELDSIZE, postFields.size()); curl_easy_setopt(_easy, CURLOPT_COPYPOSTFIELDS, postFields.c_str()); + ConnMan.registerEasyHandle(_easy); } NetworkReadStream::~NetworkReadStream() { diff --git a/backends/networking/curl/networkreadstream.h b/backends/networking/curl/networkreadstream.h index bc4b761ba7..6431a01fee 100644 --- a/backends/networking/curl/networkreadstream.h +++ b/backends/networking/curl/networkreadstream.h @@ -40,8 +40,6 @@ public: NetworkReadStream(const char *url, curl_slist *headersList, Common::String postFields); virtual ~NetworkReadStream(); - CURL *getEasyHandle() const { return _easy; } - /** * Returns true if a read failed because the stream end has been reached. * This flag is cleared by clearErr(). diff --git a/backends/networking/curl/request.h b/backends/networking/curl/request.h new file mode 100644 index 0000000000..4f901f7c94 --- /dev/null +++ b/backends/networking/curl/request.h @@ -0,0 +1,54 @@ +/* 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_NETWORKING_CURL_REQUEST_H +#define BACKENDS_NETWORKING_CURL_REQUEST_H + +namespace Networking { + +class Request { +protected: + typedef void(*Callback)(void *result); + + /** + * Callback, which should be called before Request returns true in handle(). + * That's the way Requests pass the result to the code which asked to create this request. + */ + + Callback _callback; + +public: + Request(Callback cb): _callback(cb) {}; + virtual ~Request() {}; + + /** + * Method, which does actual work. Depends on what this Request is doing. + * + * @return true if request's work is complete and it may be removed from Storage's list + */ + + virtual bool handle() = 0; +}; + +} //end of namespace Cloud + +#endif |