diff options
author | Kelly Rauchenberger <fefferburbia@gmail.com> | 2018-08-05 11:14:39 -0400 |
---|---|---|
committer | Kelly Rauchenberger <fefferburbia@gmail.com> | 2018-08-05 11:14:39 -0400 |
commit | 38203b745ae1903ba0804ed5532b78d255bea635 (patch) | |
tree | 52f57ce85e65361c534c461abc82fb1ed9768d49 /src/client.cpp | |
parent | 7c44fd17bb6be54a2ea4b60761e91053ca988977 (diff) | |
download | libtwittercpp-38203b745ae1903ba0804ed5532b78d255bea635.tar.gz libtwittercpp-38203b745ae1903ba0804ed5532b78d255bea635.tar.bz2 libtwittercpp-38203b745ae1903ba0804ed5532b78d255bea635.zip |
Added timeline polling
Because the streaming API will sunset on August 16th, it is essential to implement timeline polling so that the library can still be used to access tweets. This commit breaks the current API even for clients still using the streaming API because the OAuth connection data was pulled from twitter::client into twitter::auth. Other than that, almost everything works the same, and if a client wants to update their libtwitter++ within the next week and a half, they are free to.
Diffstat (limited to 'src/client.cpp')
-rw-r--r-- | src/client.cpp | 460 |
1 files changed, 69 insertions, 391 deletions
diff --git a/src/client.cpp b/src/client.cpp index e16e30b..820db80 100644 --- a/src/client.cpp +++ b/src/client.cpp | |||
@@ -2,385 +2,65 @@ | |||
2 | #include <sstream> | 2 | #include <sstream> |
3 | #include <set> | 3 | #include <set> |
4 | #include <algorithm> | 4 | #include <algorithm> |
5 | #include <liboauthcpp/liboauthcpp.h> | ||
6 | #include <curl_easy.h> | ||
7 | #include <curl_header.h> | ||
8 | #include <json.hpp> | 5 | #include <json.hpp> |
9 | #include <thread> | 6 | #include <thread> |
10 | 7 | #include "request.h" | |
11 | // These are here for debugging curl stuff | ||
12 | |||
13 | static | ||
14 | void dump(const char *text, | ||
15 | FILE *stream, unsigned char *ptr, size_t size) | ||
16 | { | ||
17 | size_t i; | ||
18 | size_t c; | ||
19 | unsigned int width=80; | ||
20 | |||
21 | fprintf(stream, "%s, %10.10ld bytes (0x%8.8lx)\n", | ||
22 | text, (long)size, (long)size); | ||
23 | |||
24 | for(i=0; i<size; i+= width) { | ||
25 | fprintf(stream, "%4.4lx: ", (long)i); | ||
26 | |||
27 | /* show hex to the left | ||
28 | for(c = 0; c < width; c++) { | ||
29 | if(i+c < size) | ||
30 | fprintf(stream, "%02x ", ptr[i+c]); | ||
31 | else | ||
32 | fputs(" ", stream); | ||
33 | }*/ | ||
34 | |||
35 | /* show data on the right */ | ||
36 | for(c = 0; (c < width) && (i+c < size); c++) { | ||
37 | char x = (ptr[i+c] >= 0x20 && ptr[i+c] < 0x80) ? ptr[i+c] : '.'; | ||
38 | fputc(x, stream); | ||
39 | } | ||
40 | |||
41 | fputc('\n', stream); /* newline */ | ||
42 | } | ||
43 | } | ||
44 | |||
45 | static | ||
46 | int my_trace(CURL *handle, curl_infotype type, | ||
47 | char *data, size_t size, | ||
48 | void *userp) | ||
49 | { | ||
50 | const char *text; | ||
51 | (void)handle; /* prevent compiler warning */ | ||
52 | |||
53 | switch (type) { | ||
54 | case CURLINFO_TEXT: | ||
55 | fprintf(stderr, "== Info: %s", data); | ||
56 | default: /* in case a new one is introduced to shock us */ | ||
57 | return 0; | ||
58 | |||
59 | case CURLINFO_HEADER_OUT: | ||
60 | text = "=> Send header"; | ||
61 | break; | ||
62 | case CURLINFO_DATA_OUT: | ||
63 | text = "=> Send data"; | ||
64 | break; | ||
65 | case CURLINFO_SSL_DATA_OUT: | ||
66 | text = "=> Send SSL data"; | ||
67 | break; | ||
68 | case CURLINFO_HEADER_IN: | ||
69 | text = "<= Recv header"; | ||
70 | break; | ||
71 | case CURLINFO_DATA_IN: | ||
72 | text = "<= Recv data"; | ||
73 | break; | ||
74 | case CURLINFO_SSL_DATA_IN: | ||
75 | text = "<= Recv SSL data"; | ||
76 | break; | ||
77 | } | ||
78 | |||
79 | dump(text, stderr, (unsigned char *)data, size); | ||
80 | return 0; | ||
81 | } | ||
82 | 8 | ||
83 | namespace twitter { | 9 | namespace twitter { |
84 | |||
85 | class request | ||
86 | { | ||
87 | public: | ||
88 | |||
89 | explicit request(std::string url) try | ||
90 | : _ios(_output), _conn(_ios) | ||
91 | { | ||
92 | _conn.add<CURLOPT_URL>(url.c_str()); | ||
93 | } catch (const curl::curl_easy_exception& error) | ||
94 | { | ||
95 | error.print_traceback(); | ||
96 | |||
97 | assert(false); | ||
98 | } | ||
99 | |||
100 | std::string perform() | ||
101 | { | ||
102 | try | ||
103 | { | ||
104 | _conn.perform(); | ||
105 | } catch (const curl::curl_easy_exception& error) | ||
106 | { | ||
107 | std::throw_with_nested(connection_error()); | ||
108 | } | ||
109 | |||
110 | int response_code = _conn.get_info<CURLINFO_RESPONSE_CODE>().get(); | ||
111 | std::string result = _output.str(); | ||
112 | |||
113 | if (response_code / 100 != 2) | ||
114 | { | ||
115 | nlohmann::json response_json; | ||
116 | |||
117 | try | ||
118 | { | ||
119 | response_json = nlohmann::json::parse(result); | ||
120 | } catch (const std::invalid_argument& e) | ||
121 | { | ||
122 | std::throw_with_nested(invalid_response(result)); | ||
123 | } | ||
124 | |||
125 | for (nlohmann::json& error : response_json["errors"]) | ||
126 | { | ||
127 | int error_code; | ||
128 | std::string error_message; | ||
129 | |||
130 | try | ||
131 | { | ||
132 | error_code = error["code"].get<int>(); | ||
133 | error_message = error["message"].get<std::string>(); | ||
134 | } catch (const std::domain_error& e) | ||
135 | { | ||
136 | std::throw_with_nested(invalid_response(result)); | ||
137 | } | ||
138 | |||
139 | switch (error_code) | ||
140 | { | ||
141 | case 32: | ||
142 | case 135: | ||
143 | case 215: | ||
144 | throw bad_auth(error_message); | ||
145 | |||
146 | case 44: | ||
147 | throw invalid_media(error_message); | ||
148 | |||
149 | case 64: | ||
150 | throw account_suspended(error_message); | ||
151 | |||
152 | case 88: | ||
153 | throw rate_limit_exceeded(error_message); | ||
154 | |||
155 | case 89: | ||
156 | throw bad_token(error_message); | ||
157 | |||
158 | case 130: | ||
159 | throw server_overloaded(error_message); | ||
160 | |||
161 | case 131: | ||
162 | throw server_error(error_message); | ||
163 | |||
164 | case 185: | ||
165 | throw update_limit_exceeded(error_message); | ||
166 | |||
167 | case 186: | ||
168 | throw bad_length(error_message); | ||
169 | |||
170 | case 187: | ||
171 | throw duplicate_status(error_message); | ||
172 | |||
173 | case 226: | ||
174 | throw suspected_spam(error_message); | ||
175 | |||
176 | case 261: | ||
177 | throw write_restricted(error_message); | ||
178 | } | ||
179 | } | ||
180 | 10 | ||
181 | if (response_code == 429) | 11 | client::client( |
182 | { | 12 | const auth& _arg) : |
183 | throw rate_limit_exceeded("HTTP 429 Too Many Requests"); | 13 | auth_(_arg), |
184 | } else if (response_code == 500) | 14 | currentUser_( |
185 | { | 15 | get(auth_, |
186 | throw server_error("HTTP 500 Internal Server Error"); | ||
187 | } else if (response_code == 502) | ||
188 | { | ||
189 | throw server_unavailable("HTTP 502 Bad Gateway"); | ||
190 | } else if (response_code == 503) | ||
191 | { | ||
192 | throw server_overloaded("HTTP 503 Service Unavailable"); | ||
193 | } else if (response_code == 504) | ||
194 | { | ||
195 | throw server_timeout("HTTP 504 Gateway Timeout"); | ||
196 | } | ||
197 | |||
198 | throw unknown_error(response_code, result); | ||
199 | } | ||
200 | |||
201 | return result; | ||
202 | } | ||
203 | |||
204 | private: | ||
205 | |||
206 | std::ostringstream _output; | ||
207 | curl::curl_ios<std::ostringstream> _ios; | ||
208 | |||
209 | protected: | ||
210 | |||
211 | curl::curl_easy _conn; | ||
212 | }; | ||
213 | |||
214 | class get : public request | ||
215 | { | ||
216 | public: | ||
217 | |||
218 | get(const OAuth::Client& oauth_client, std::string url) try | ||
219 | : request(url) | ||
220 | { | ||
221 | std::string oauth_header = oauth_client.getFormattedHttpHeader(OAuth::Http::Get, url, ""); | ||
222 | if (!oauth_header.empty()) | ||
223 | { | ||
224 | _headers.add(std::move(oauth_header)); | ||
225 | } | ||
226 | |||
227 | _conn.add<CURLOPT_HTTPHEADER>(_headers.get()); | ||
228 | } catch (const OAuth::ParseError& error) | ||
229 | { | ||
230 | std::cout << "Error generating OAuth header:" << std::endl; | ||
231 | std::cout << error.what() << std::endl; | ||
232 | std::cout << "This is likely due to a malformed URL." << std::endl; | ||
233 | |||
234 | assert(false); | ||
235 | } catch (const curl::curl_easy_exception& error) | ||
236 | { | ||
237 | error.print_traceback(); | ||
238 | |||
239 | assert(false); | ||
240 | } | ||
241 | |||
242 | private: | ||
243 | |||
244 | curl::curl_header _headers; | ||
245 | }; | ||
246 | |||
247 | class post : public request | ||
248 | { | ||
249 | public: | ||
250 | |||
251 | post(const OAuth::Client& oauth_client, std::string url, std::string datastr) try | ||
252 | : request(url) | ||
253 | { | ||
254 | std::string oauth_header = oauth_client.getFormattedHttpHeader(OAuth::Http::Post, url, datastr); | ||
255 | if (!oauth_header.empty()) | ||
256 | { | ||
257 | _headers.add(std::move(oauth_header)); | ||
258 | } | ||
259 | |||
260 | _conn.add<CURLOPT_HTTPHEADER>(_headers.get()); | ||
261 | _conn.add<CURLOPT_COPYPOSTFIELDS>(datastr.c_str()); | ||
262 | } catch (const OAuth::ParseError& error) | ||
263 | { | ||
264 | std::cout << "Error generating OAuth header:" << std::endl; | ||
265 | std::cout << error.what() << std::endl; | ||
266 | std::cout << "This is likely due to a malformed URL." << std::endl; | ||
267 | |||
268 | assert(false); | ||
269 | } catch (const curl::curl_easy_exception& error) | ||
270 | { | ||
271 | error.print_traceback(); | ||
272 | |||
273 | assert(false); | ||
274 | } | ||
275 | |||
276 | private: | ||
277 | |||
278 | curl::curl_header _headers; | ||
279 | }; | ||
280 | |||
281 | class multipost : public request | ||
282 | { | ||
283 | public: | ||
284 | |||
285 | multipost(const OAuth::Client& oauth_client, std::string url, const curl_httppost* fields) try | ||
286 | : request(url) | ||
287 | { | ||
288 | std::string oauth_header = oauth_client.getFormattedHttpHeader(OAuth::Http::Post, url, ""); | ||
289 | if (!oauth_header.empty()) | ||
290 | { | ||
291 | _headers.add(std::move(oauth_header)); | ||
292 | } | ||
293 | |||
294 | _conn.add<CURLOPT_HTTPHEADER>(_headers.get()); | ||
295 | _conn.add<CURLOPT_HTTPPOST>(fields); | ||
296 | } catch (const OAuth::ParseError& error) | ||
297 | { | ||
298 | std::cout << "Error generating OAuth header:" << std::endl; | ||
299 | std::cout << error.what() << std::endl; | ||
300 | std::cout << "This is likely due to a malformed URL." << std::endl; | ||
301 | |||
302 | assert(false); | ||
303 | } catch (const curl::curl_easy_exception& error) | ||
304 | { | ||
305 | error.print_traceback(); | ||
306 | |||
307 | assert(false); | ||
308 | } | ||
309 | |||
310 | private: | ||
311 | |||
312 | curl::curl_header _headers; | ||
313 | }; | ||
314 | |||
315 | client::client(const auth& _arg) | ||
316 | { | ||
317 | _oauth_consumer = | ||
318 | make_unique<OAuth::Consumer>( | ||
319 | _arg.getConsumerKey(), | ||
320 | _arg.getConsumerSecret()); | ||
321 | |||
322 | _oauth_token = | ||
323 | make_unique<OAuth::Token>( | ||
324 | _arg.getAccessKey(), | ||
325 | _arg.getAccessSecret()); | ||
326 | |||
327 | _oauth_client = | ||
328 | make_unique<OAuth::Client>( | ||
329 | _oauth_consumer.get(), | ||
330 | _oauth_token.get()); | ||
331 | |||
332 | _current_user = | ||
333 | make_unique<user>( | ||
334 | get(*_oauth_client, | ||
335 | "https://api.twitter.com/1.1/account/verify_credentials.json") | 16 | "https://api.twitter.com/1.1/account/verify_credentials.json") |
336 | .perform()); | 17 | .perform()) |
18 | { | ||
337 | } | 19 | } |
338 | 20 | ||
339 | client::~client() = default; | ||
340 | |||
341 | tweet client::updateStatus(std::string msg, std::list<long> media_ids) const | 21 | tweet client::updateStatus(std::string msg, std::list<long> media_ids) const |
342 | { | 22 | { |
343 | std::stringstream datastrstream; | 23 | std::stringstream datastrstream; |
344 | datastrstream << "status=" << OAuth::PercentEncode(msg); | 24 | datastrstream << "status=" << OAuth::PercentEncode(msg); |
345 | 25 | ||
346 | if (!media_ids.empty()) | 26 | if (!media_ids.empty()) |
347 | { | 27 | { |
348 | datastrstream << "&media_ids="; | 28 | datastrstream << "&media_ids="; |
349 | datastrstream << twitter::implode(std::begin(media_ids), std::end(media_ids), ","); | 29 | datastrstream << twitter::implode(std::begin(media_ids), std::end(media_ids), ","); |
350 | } | 30 | } |
351 | 31 | ||
352 | return tweet( | 32 | return tweet( |
353 | post(*_oauth_client, | 33 | post(auth_, |
354 | "https://api.twitter.com/1.1/statuses/update.json", | 34 | "https://api.twitter.com/1.1/statuses/update.json", |
355 | datastrstream.str()) | 35 | datastrstream.str()) |
356 | .perform()); | 36 | .perform()); |
357 | } | 37 | } |
358 | 38 | ||
359 | tweet client::replyToTweet(std::string msg, tweet_id in_response_to, std::list<long> media_ids) const | 39 | tweet client::replyToTweet(std::string msg, tweet_id in_response_to, std::list<long> media_ids) const |
360 | { | 40 | { |
361 | std::stringstream datastrstream; | 41 | std::stringstream datastrstream; |
362 | datastrstream << "status=" << OAuth::PercentEncode(msg); | 42 | datastrstream << "status=" << OAuth::PercentEncode(msg); |
363 | datastrstream << "&in_reply_to_status_id="; | 43 | datastrstream << "&in_reply_to_status_id="; |
364 | datastrstream << in_response_to; | 44 | datastrstream << in_response_to; |
365 | 45 | ||
366 | if (!media_ids.empty()) | 46 | if (!media_ids.empty()) |
367 | { | 47 | { |
368 | datastrstream << "&media_ids="; | 48 | datastrstream << "&media_ids="; |
369 | datastrstream << twitter::implode(std::begin(media_ids), std::end(media_ids), ","); | 49 | datastrstream << twitter::implode(std::begin(media_ids), std::end(media_ids), ","); |
370 | } | 50 | } |
371 | 51 | ||
372 | return tweet( | 52 | return tweet( |
373 | post(*_oauth_client, | 53 | post(auth_, |
374 | "https://api.twitter.com/1.1/statuses/update.json", | 54 | "https://api.twitter.com/1.1/statuses/update.json", |
375 | datastrstream.str()) | 55 | datastrstream.str()) |
376 | .perform()); | 56 | .perform()); |
377 | } | 57 | } |
378 | 58 | ||
379 | long client::uploadMedia(std::string media_type, const char* data, long data_length) const try | 59 | long client::uploadMedia(std::string media_type, const char* data, long data_length) const try |
380 | { | 60 | { |
381 | curl::curl_form form; | 61 | curl::curl_form form; |
382 | std::string str_data_length = std::to_string(data_length); | 62 | std::string str_data_length = std::to_string(data_length); |
383 | 63 | ||
384 | curl::curl_pair<CURLformoption, std::string> command_name(CURLFORM_COPYNAME, "command"); | 64 | curl::curl_pair<CURLformoption, std::string> command_name(CURLFORM_COPYNAME, "command"); |
385 | curl::curl_pair<CURLformoption, std::string> command_cont(CURLFORM_COPYCONTENTS, "INIT"); | 65 | curl::curl_pair<CURLformoption, std::string> command_cont(CURLFORM_COPYCONTENTS, "INIT"); |
386 | curl::curl_pair<CURLformoption, std::string> bytes_name(CURLFORM_COPYNAME, "total_bytes"); | 66 | curl::curl_pair<CURLformoption, std::string> bytes_name(CURLFORM_COPYNAME, "total_bytes"); |
@@ -397,15 +77,15 @@ namespace twitter { | |||
397 | curl::curl_pair<CURLformoption, std::string> category_cont(CURLFORM_COPYCONTENTS, "tweet_gif"); | 77 | curl::curl_pair<CURLformoption, std::string> category_cont(CURLFORM_COPYCONTENTS, "tweet_gif"); |
398 | form.add(category_name, category_cont); | 78 | form.add(category_name, category_cont); |
399 | } | 79 | } |
400 | 80 | ||
401 | std::string init_response = | 81 | std::string init_response = |
402 | multipost(*_oauth_client, | 82 | multipost(auth_, |
403 | "https://upload.twitter.com/1.1/media/upload.json", | 83 | "https://upload.twitter.com/1.1/media/upload.json", |
404 | form.get()) | 84 | form.get()) |
405 | .perform(); | 85 | .perform(); |
406 | 86 | ||
407 | long media_id; | 87 | long media_id; |
408 | 88 | ||
409 | try | 89 | try |
410 | { | 90 | { |
411 | nlohmann::json response_json = nlohmann::json::parse(init_response); | 91 | nlohmann::json response_json = nlohmann::json::parse(init_response); |
@@ -429,29 +109,29 @@ namespace twitter { | |||
429 | { | 109 | { |
430 | assert(false); | 110 | assert(false); |
431 | } | 111 | } |
432 | 112 | ||
433 | multipost(*_oauth_client, "https://upload.twitter.com/1.1/media/upload.json", append_form_post).perform(); | 113 | multipost(auth_, "https://upload.twitter.com/1.1/media/upload.json", append_form_post).perform(); |
434 | 114 | ||
435 | curl_formfree(append_form_post); | 115 | curl_formfree(append_form_post); |
436 | 116 | ||
437 | curl::curl_form finalize_form; | 117 | curl::curl_form finalize_form; |
438 | std::string str_media_id = std::to_string(media_id); | 118 | std::string str_media_id = std::to_string(media_id); |
439 | 119 | ||
440 | curl::curl_pair<CURLformoption, std::string> command3_name(CURLFORM_COPYNAME, "command"); | 120 | curl::curl_pair<CURLformoption, std::string> command3_name(CURLFORM_COPYNAME, "command"); |
441 | curl::curl_pair<CURLformoption, std::string> command3_cont(CURLFORM_COPYCONTENTS, "FINALIZE"); | 121 | curl::curl_pair<CURLformoption, std::string> command3_cont(CURLFORM_COPYCONTENTS, "FINALIZE"); |
442 | curl::curl_pair<CURLformoption, std::string> media_id_name(CURLFORM_COPYNAME, "media_id"); | 122 | curl::curl_pair<CURLformoption, std::string> media_id_name(CURLFORM_COPYNAME, "media_id"); |
443 | curl::curl_pair<CURLformoption, std::string> media_id_cont(CURLFORM_COPYCONTENTS, str_media_id); | 123 | curl::curl_pair<CURLformoption, std::string> media_id_cont(CURLFORM_COPYCONTENTS, str_media_id); |
444 | finalize_form.add(command3_name, command3_cont); | 124 | finalize_form.add(command3_name, command3_cont); |
445 | finalize_form.add(media_id_name, media_id_cont); | 125 | finalize_form.add(media_id_name, media_id_cont); |
446 | 126 | ||
447 | std::string finalize_response = | 127 | std::string finalize_response = |
448 | multipost(*_oauth_client, | 128 | multipost(auth_, |
449 | "https://upload.twitter.com/1.1/media/upload.json", | 129 | "https://upload.twitter.com/1.1/media/upload.json", |
450 | finalize_form.get()) | 130 | finalize_form.get()) |
451 | .perform(); | 131 | .perform(); |
452 | 132 | ||
453 | nlohmann::json finalize_json; | 133 | nlohmann::json finalize_json; |
454 | 134 | ||
455 | try | 135 | try |
456 | { | 136 | { |
457 | finalize_json = nlohmann::json::parse(finalize_response); | 137 | finalize_json = nlohmann::json::parse(finalize_response); |
@@ -459,26 +139,26 @@ namespace twitter { | |||
459 | { | 139 | { |
460 | std::throw_with_nested(invalid_response(finalize_response)); | 140 | std::throw_with_nested(invalid_response(finalize_response)); |
461 | } | 141 | } |
462 | 142 | ||
463 | if (finalize_json.find("processing_info") != finalize_json.end()) | 143 | if (finalize_json.find("processing_info") != finalize_json.end()) |
464 | { | 144 | { |
465 | std::stringstream datastr; | 145 | std::stringstream datastr; |
466 | datastr << "https://upload.twitter.com/1.1/media/upload.json?command=STATUS&media_id=" << media_id; | 146 | datastr << "https://upload.twitter.com/1.1/media/upload.json?command=STATUS&media_id=" << media_id; |
467 | 147 | ||
468 | for (;;) | 148 | for (;;) |
469 | { | 149 | { |
470 | std::string status_response = get(*_oauth_client, datastr.str()).perform(); | 150 | std::string status_response = get(auth_, datastr.str()).perform(); |
471 | 151 | ||
472 | try | 152 | try |
473 | { | 153 | { |
474 | nlohmann::json status_json = nlohmann::json::parse(status_response); | 154 | nlohmann::json status_json = nlohmann::json::parse(status_response); |
475 | std::string state = status_json["processing_info"]["state"].get<std::string>(); | 155 | std::string state = status_json["processing_info"]["state"].get<std::string>(); |
476 | 156 | ||
477 | if (state == "succeeded") | 157 | if (state == "succeeded") |
478 | { | 158 | { |
479 | break; | 159 | break; |
480 | } | 160 | } |
481 | 161 | ||
482 | int ttw = status_json["processing_info"]["check_after_secs"].get<int>(); | 162 | int ttw = status_json["processing_info"]["check_after_secs"].get<int>(); |
483 | std::this_thread::sleep_for(std::chrono::seconds(ttw)); | 163 | std::this_thread::sleep_for(std::chrono::seconds(ttw)); |
484 | } catch (const std::invalid_argument& error) | 164 | } catch (const std::invalid_argument& error) |
@@ -490,20 +170,18 @@ namespace twitter { | |||
490 | } | 170 | } |
491 | } | 171 | } |
492 | } | 172 | } |
493 | 173 | ||
494 | return media_id; | 174 | return media_id; |
495 | } catch (const curl::curl_exception& error) | 175 | } catch (const curl::curl_exception& error) |
496 | { | 176 | { |
497 | error.print_traceback(); | 177 | std::throw_with_nested(connection_error()); |
498 | |||
499 | assert(false); | ||
500 | } | 178 | } |
501 | 179 | ||
502 | std::set<user_id> client::getFriends(user_id id) const | 180 | std::set<user_id> client::getFriends(user_id id) const |
503 | { | 181 | { |
504 | long long cursor = -1; | 182 | long long cursor = -1; |
505 | std::set<user_id> result; | 183 | std::set<user_id> result; |
506 | 184 | ||
507 | while (cursor != 0) | 185 | while (cursor != 0) |
508 | { | 186 | { |
509 | std::stringstream urlstream; | 187 | std::stringstream urlstream; |
@@ -511,14 +189,14 @@ namespace twitter { | |||
511 | urlstream << id; | 189 | urlstream << id; |
512 | urlstream << "&cursor="; | 190 | urlstream << "&cursor="; |
513 | urlstream << cursor; | 191 | urlstream << cursor; |
514 | 192 | ||
515 | std::string url = urlstream.str(); | 193 | std::string url = urlstream.str(); |
516 | std::string response_data = get(*_oauth_client, url).perform(); | 194 | std::string response_data = get(auth_, url).perform(); |
517 | 195 | ||
518 | try | 196 | try |
519 | { | 197 | { |
520 | nlohmann::json rjs = nlohmann::json::parse(response_data); | 198 | nlohmann::json rjs = nlohmann::json::parse(response_data); |
521 | 199 | ||
522 | cursor = rjs["next_cursor"].get<long long>(); | 200 | cursor = rjs["next_cursor"].get<long long>(); |
523 | result.insert(std::begin(rjs["ids"]), std::end(rjs["ids"])); | 201 | result.insert(std::begin(rjs["ids"]), std::end(rjs["ids"])); |
524 | } catch (const std::invalid_argument& error) | 202 | } catch (const std::invalid_argument& error) |
@@ -529,25 +207,25 @@ namespace twitter { | |||
529 | std::throw_with_nested(invalid_response(response_data)); | 207 | std::throw_with_nested(invalid_response(response_data)); |
530 | } | 208 | } |
531 | } | 209 | } |
532 | 210 | ||
533 | return result; | 211 | return result; |
534 | } | 212 | } |
535 | 213 | ||
536 | std::set<user_id> client::getFriends(const user& id) const | 214 | std::set<user_id> client::getFriends(const user& id) const |
537 | { | 215 | { |
538 | return getFriends(id.getID()); | 216 | return getFriends(id.getID()); |
539 | } | 217 | } |
540 | 218 | ||
541 | std::set<user_id> client::getFriends() const | 219 | std::set<user_id> client::getFriends() const |
542 | { | 220 | { |
543 | return getFriends(getUser().getID()); | 221 | return getFriends(getUser().getID()); |
544 | } | 222 | } |
545 | 223 | ||
546 | std::set<user_id> client::getFollowers(user_id id) const | 224 | std::set<user_id> client::getFollowers(user_id id) const |
547 | { | 225 | { |
548 | long long cursor = -1; | 226 | long long cursor = -1; |
549 | std::set<user_id> result; | 227 | std::set<user_id> result; |
550 | 228 | ||
551 | while (cursor != 0) | 229 | while (cursor != 0) |
552 | { | 230 | { |
553 | std::stringstream urlstream; | 231 | std::stringstream urlstream; |
@@ -555,14 +233,14 @@ namespace twitter { | |||
555 | urlstream << id; | 233 | urlstream << id; |
556 | urlstream << "&cursor="; | 234 | urlstream << "&cursor="; |
557 | urlstream << cursor; | 235 | urlstream << cursor; |
558 | 236 | ||
559 | std::string url = urlstream.str(); | 237 | std::string url = urlstream.str(); |
560 | std::string response_data = get(*_oauth_client, url).perform(); | 238 | std::string response_data = get(auth_, url).perform(); |
561 | 239 | ||
562 | try | 240 | try |
563 | { | 241 | { |
564 | nlohmann::json rjs = nlohmann::json::parse(response_data); | 242 | nlohmann::json rjs = nlohmann::json::parse(response_data); |
565 | 243 | ||
566 | cursor = rjs["next_cursor"].get<long long>(); | 244 | cursor = rjs["next_cursor"].get<long long>(); |
567 | result.insert(std::begin(rjs["ids"]), std::end(rjs["ids"])); | 245 | result.insert(std::begin(rjs["ids"]), std::end(rjs["ids"])); |
568 | } catch (const std::invalid_argument& error) | 246 | } catch (const std::invalid_argument& error) |
@@ -573,43 +251,43 @@ namespace twitter { | |||
573 | std::throw_with_nested(invalid_response(response_data)); | 251 | std::throw_with_nested(invalid_response(response_data)); |
574 | } | 252 | } |
575 | } | 253 | } |
576 | 254 | ||
577 | return result; | 255 | return result; |
578 | } | 256 | } |
579 | 257 | ||
580 | std::set<user_id> client::getFollowers(const user& id) const | 258 | std::set<user_id> client::getFollowers(const user& id) const |
581 | { | 259 | { |
582 | return getFollowers(id.getID()); | 260 | return getFollowers(id.getID()); |
583 | } | 261 | } |
584 | 262 | ||
585 | std::set<user_id> client::getFollowers() const | 263 | std::set<user_id> client::getFollowers() const |
586 | { | 264 | { |
587 | return getFollowers(getUser().getID()); | 265 | return getFollowers(getUser().getID()); |
588 | } | 266 | } |
589 | 267 | ||
590 | void client::follow(user_id toFollow) const | 268 | void client::follow(user_id toFollow) const |
591 | { | 269 | { |
592 | std::stringstream datastrstream; | 270 | std::stringstream datastrstream; |
593 | datastrstream << "follow=true&user_id="; | 271 | datastrstream << "follow=true&user_id="; |
594 | datastrstream << toFollow; | 272 | datastrstream << toFollow; |
595 | 273 | ||
596 | post(*_oauth_client, "https://api.twitter.com/1.1/friendships/create.json", datastrstream.str()).perform(); | 274 | post(auth_, "https://api.twitter.com/1.1/friendships/create.json", datastrstream.str()).perform(); |
597 | } | 275 | } |
598 | 276 | ||
599 | void client::follow(const user& toFollow) const | 277 | void client::follow(const user& toFollow) const |
600 | { | 278 | { |
601 | return follow(toFollow.getID()); | 279 | return follow(toFollow.getID()); |
602 | } | 280 | } |
603 | 281 | ||
604 | void client::unfollow(user_id toUnfollow) const | 282 | void client::unfollow(user_id toUnfollow) const |
605 | { | 283 | { |
606 | std::stringstream datastrstream; | 284 | std::stringstream datastrstream; |
607 | datastrstream << "user_id="; | 285 | datastrstream << "user_id="; |
608 | datastrstream << toUnfollow; | 286 | datastrstream << toUnfollow; |
609 | 287 | ||
610 | post(*_oauth_client, "https://api.twitter.com/1.1/friendships/destroy.json", datastrstream.str()).perform(); | 288 | post(auth_, "https://api.twitter.com/1.1/friendships/destroy.json", datastrstream.str()).perform(); |
611 | } | 289 | } |
612 | 290 | ||
613 | void client::unfollow(const user& toUnfollow) const | 291 | void client::unfollow(const user& toUnfollow) const |
614 | { | 292 | { |
615 | return unfollow(toUnfollow.getID()); | 293 | return unfollow(toUnfollow.getID()); |
@@ -617,23 +295,23 @@ namespace twitter { | |||
617 | 295 | ||
618 | const user& client::getUser() const | 296 | const user& client::getUser() const |
619 | { | 297 | { |
620 | return *_current_user; | 298 | return currentUser_; |
621 | } | 299 | } |
622 | 300 | ||
623 | const configuration& client::getConfiguration() const | 301 | const configuration& client::getConfiguration() const |
624 | { | 302 | { |
625 | if (!_configuration || (difftime(time(NULL), _last_configuration_update) > 60*60*24)) | 303 | if (!_configuration || (difftime(time(NULL), _last_configuration_update) > 60*60*24)) |
626 | { | 304 | { |
627 | _configuration = | 305 | _configuration = |
628 | make_unique<configuration>( | 306 | std::make_unique<configuration>( |
629 | get(*_oauth_client, | 307 | get(auth_, |
630 | "https://api.twitter.com/1.1/help/configuration.json") | 308 | "https://api.twitter.com/1.1/help/configuration.json") |
631 | .perform()); | 309 | .perform()); |
632 | 310 | ||
633 | _last_configuration_update = time(NULL); | 311 | _last_configuration_update = time(NULL); |
634 | } | 312 | } |
635 | 313 | ||
636 | return *_configuration; | 314 | return *_configuration; |
637 | } | 315 | } |
638 | 316 | ||
639 | }; | 317 | }; |