-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathAsyncHTTPGETClient.cpp
More file actions
121 lines (96 loc) · 3.04 KB
/
Copy pathAsyncHTTPGETClient.cpp
File metadata and controls
121 lines (96 loc) · 3.04 KB
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
#include "AsyncHTTPGETClient.hpp"
#include <stdexcept>
/* Error message, and received data */
static char errorBuffer[CURL_ERROR_SIZE];
static std::string buffer;
/* Writer function for libCURL */
static int writer(char * data, std::size_t size, std::size_t nmemb,
std::string * writerData) {
if (writerData == nullptr) {
return 0;
}
writerData->append(data, size * nmemb);
return size * nmemb;
}
AsyncHTTPGETClient::Request::Request(const std::string & url, const std::string & postFields,
const std::function<void(CURL * const, const CURLcode, const std::string &)> callback)
: url(url),
postFields(postFields),
callback(callback) { }
AsyncHTTPGETClient::AsyncHTTPGETClient()
: curl(curl_easy_init()),
terminateThread(false),
requestThread([this] { processRequests(); }) {
CURLcode code;
if (curl == nullptr) {
throw std::runtime_error("Couldn't initialize libCURL!");
}
if (curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer) != CURLE_OK) {
throw std::runtime_error("Couldn't set the libCURL error buffer!");
}
code = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer);
if (code != CURLE_OK) {
throw std::runtime_error("Couldn't set the libCURL writer function! " + std::string(errorBuffer));
}
code = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
if (code != CURLE_OK) {
throw std::runtime_error("Couldn't set the libCURL write buffer! " + std::string(errorBuffer));
}
//curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 4);
}
AsyncHTTPGETClient::~AsyncHTTPGETClient() {
terminateThread = true;
cv.notify_all();
requestThread.join();
if (curl) {
curl_easy_cleanup(curl);
}
}
void AsyncHTTPGETClient::removeRequests(const std::string & url) {
/* Iterating queues isn't the best thing one can do */
queueLock.lock();
size_t queueSize = requestQueue.size();
while (queueSize--) {
Request req = requestQueue.front();
requestQueue.pop();
if (req.url != url) {
requestQueue.push(req);
}
}
queueLock.unlock();
}
void AsyncHTTPGETClient::queueRequest(const AsyncHTTPGETClient::Request req) {
std::unique_lock<std::mutex> lck(waitLock);
queueLock.lock();
requestQueue.push(req);
queueLock.unlock();
cv.notify_all();
}
void AsyncHTTPGETClient::processRequests() {
while (!terminateThread) {
std::unique_lock<std::mutex> lck(waitLock);
queueLock.lock(); /* Seems like this needs too much (un)locking for my tastes */
while (requestQueue.size() != 0) {
CURLcode code;
Request req = requestQueue.front();
requestQueue.pop();
queueLock.unlock();
std::string url = req.url;
if (req.postFields.size() > 0) {
url += "?" + req.postFields;
}
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
code = curl_easy_perform(curl);
/* NOTE: This is called from the request thread. */
req.callback(curl, code, buffer);
buffer.clear();
queueLock.lock();
}
queueLock.unlock();
cv.wait(lck);
}
}
CURL * const AsyncHTTPGETClient::getCurl() {
return curl;
}