diff options
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 | }; |