aboutsummaryrefslogtreecommitdiff
path: root/backends/networking/curl/connectionmanager.h
blob: 5fd19d78b504510d6b0bb471a92243059c534344 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/* 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_CONNECTIONMANAGER_H
#define BACKENDS_NETWORKING_CURL_CONNECTIONMANAGER_H

#include "backends/networking/curl/cloudicon.h"
#include "backends/networking/curl/request.h"
#include "common/str.h"
#include "common/singleton.h"
#include "common/hashmap.h"
#include "common/mutex.h"

typedef void CURL;
typedef void CURLM;
struct curl_slist;

namespace Networking {

class NetworkReadStream;

class ConnectionManager : public Common::Singleton<ConnectionManager> {
	static const uint32 FRAMES_PER_SECOND = 20;
	static const uint32 TIMER_INTERVAL = 1000000 / FRAMES_PER_SECOND;
	static const uint32 CLOUD_PERIOD = 20; //every 20th frame
	static const uint32 CURL_PERIOD = 1; //every frame

	friend void connectionsThread(void *); //calls handle()

	typedef Common::BaseCallback<Request *> *RequestCallback;

	/**
	 * RequestWithCallback is used by ConnectionManager to
	 * storage the Request and a callback which should be
	 * called on Request delete.
	 *
	 * Usually one won't need to pass such callback, but
	 * in some cases you'd like to know whether Request is
	 * still running.
	 *
	 * For example, Cloud::Storage is keeping track of how
	 * many Requests are running, and thus it needs to know
	 * that Request was destroyed to decrease its counter.
	 *
	 * onDeleteCallback is called with *invalid* pointer.
	 * ConnectionManager deletes Request first and then passes
	 * the pointer to the callback. One may use the address
	 * to find it in own HashMap or Array and remove it.
	 * So, again, this pointer is for information only. One
	 * cannot use it.
	 */
	struct RequestWithCallback {
		Request *request;
		RequestCallback onDeleteCallback;

		RequestWithCallback(Request *rq = nullptr, RequestCallback cb = nullptr): request(rq), onDeleteCallback(cb) {}
	};

	CURLM *_multi;
	bool _timerStarted;
	Common::Array<RequestWithCallback> _requests, _addedRequests;
	Common::Mutex _handleMutex, _addedRequestsMutex;
	CloudIcon _icon;
	uint32 _frame;

	void startTimer(int interval = TIMER_INTERVAL);
	void stopTimer();
	void handle();
	void interateRequests();
	void processTransfers();
	bool hasAddedRequests();

public:
	ConnectionManager();
	virtual ~ConnectionManager();

	/**
	 * 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) const;

	/**
	 * Use this method to add new Request into manager's queue.
	 * Manager will periodically call handle() method of these
	 * Requests until they set their state to FINISHED.
	 *
	 * If Request's state is RETRY, handleRetry() is called instead.
	 *
	 * The passed callback would be called after Request is deleted.
	 *
	 * @note This method starts the timer if it's not started yet.
	 *
	 * @return the same Request pointer, just as a shortcut
	 */
	Request *addRequest(Request *request, RequestCallback callback = nullptr);

	/** Shows a "cloud disabled" icon for a three seconds. */
	void showCloudDisabledIcon();

	/** Return URL-encoded version of given string. */
	Common::String urlEncode(Common::String s) const;

	static uint32 getCloudRequestsPeriodInMicroseconds();
};

/** Shortcut for accessing the connection manager. */
#define ConnMan		Networking::ConnectionManager::instance()

} // End of namespace Networking

#endif