about summary refs log tree commit diff stats
path: root/src/client.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/client.cpp')
-rw-r--r--src/client.cpp460
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
13static
14void 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
45static
46int 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
83namespace twitter { 9namespace 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};