about summary refs log tree commit diff stats
path: root/src/client.cpp
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2018-08-05 11:14:39 -0400
committerKelly Rauchenberger <fefferburbia@gmail.com>2018-08-05 11:14:39 -0400
commit38203b745ae1903ba0804ed5532b78d255bea635 (patch)
tree52f57ce85e65361c534c461abc82fb1ed9768d49 /src/client.cpp
parent7c44fd17bb6be54a2ea4b60761e91053ca988977 (diff)
downloadlibtwittercpp-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.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};