diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/client.cpp | 220 | ||||
| -rw-r--r-- | src/client.h | 30 |
2 files changed, 125 insertions, 125 deletions
| diff --git a/src/client.cpp b/src/client.cpp index c2ef06f..6fea80a 100644 --- a/src/client.cpp +++ b/src/client.cpp | |||
| @@ -17,13 +17,13 @@ void dump(const char *text, | |||
| 17 | size_t i; | 17 | size_t i; |
| 18 | size_t c; | 18 | size_t c; |
| 19 | unsigned int width=80; | 19 | unsigned int width=80; |
| 20 | 20 | ||
| 21 | fprintf(stream, "%s, %10.10ld bytes (0x%8.8lx)\n", | 21 | fprintf(stream, "%s, %10.10ld bytes (0x%8.8lx)\n", |
| 22 | text, (long)size, (long)size); | 22 | text, (long)size, (long)size); |
| 23 | 23 | ||
| 24 | for(i=0; i<size; i+= width) { | 24 | for(i=0; i<size; i+= width) { |
| 25 | fprintf(stream, "%4.4lx: ", (long)i); | 25 | fprintf(stream, "%4.4lx: ", (long)i); |
| 26 | 26 | ||
| 27 | /* show hex to the left | 27 | /* show hex to the left |
| 28 | for(c = 0; c < width; c++) { | 28 | for(c = 0; c < width; c++) { |
| 29 | if(i+c < size) | 29 | if(i+c < size) |
| @@ -31,17 +31,17 @@ void dump(const char *text, | |||
| 31 | else | 31 | else |
| 32 | fputs(" ", stream); | 32 | fputs(" ", stream); |
| 33 | }*/ | 33 | }*/ |
| 34 | 34 | ||
| 35 | /* show data on the right */ | 35 | /* show data on the right */ |
| 36 | for(c = 0; (c < width) && (i+c < size); c++) { | 36 | for(c = 0; (c < width) && (i+c < size); c++) { |
| 37 | char x = (ptr[i+c] >= 0x20 && ptr[i+c] < 0x80) ? ptr[i+c] : '.'; | 37 | char x = (ptr[i+c] >= 0x20 && ptr[i+c] < 0x80) ? ptr[i+c] : '.'; |
| 38 | fputc(x, stream); | 38 | fputc(x, stream); |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | fputc('\n', stream); /* newline */ | 41 | fputc('\n', stream); /* newline */ |
| 42 | } | 42 | } |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | static | 45 | static |
| 46 | int my_trace(CURL *handle, curl_infotype type, | 46 | int my_trace(CURL *handle, curl_infotype type, |
| 47 | char *data, size_t size, | 47 | char *data, size_t size, |
| @@ -49,13 +49,13 @@ int my_trace(CURL *handle, curl_infotype type, | |||
| 49 | { | 49 | { |
| 50 | const char *text; | 50 | const char *text; |
| 51 | (void)handle; /* prevent compiler warning */ | 51 | (void)handle; /* prevent compiler warning */ |
| 52 | 52 | ||
| 53 | switch (type) { | 53 | switch (type) { |
| 54 | case CURLINFO_TEXT: | 54 | case CURLINFO_TEXT: |
| 55 | fprintf(stderr, "== Info: %s", data); | 55 | fprintf(stderr, "== Info: %s", data); |
| 56 | default: /* in case a new one is introduced to shock us */ | 56 | default: /* in case a new one is introduced to shock us */ |
| 57 | return 0; | 57 | return 0; |
| 58 | 58 | ||
| 59 | case CURLINFO_HEADER_OUT: | 59 | case CURLINFO_HEADER_OUT: |
| 60 | text = "=> Send header"; | 60 | text = "=> Send header"; |
| 61 | break; | 61 | break; |
| @@ -75,17 +75,17 @@ int my_trace(CURL *handle, curl_infotype type, | |||
| 75 | text = "<= Recv SSL data"; | 75 | text = "<= Recv SSL data"; |
| 76 | break; | 76 | break; |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | dump(text, stderr, (unsigned char *)data, size); | 79 | dump(text, stderr, (unsigned char *)data, size); |
| 80 | return 0; | 80 | return 0; |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | namespace twitter { | 83 | namespace twitter { |
| 84 | 84 | ||
| 85 | class request | 85 | class request |
| 86 | { | 86 | { |
| 87 | public: | 87 | public: |
| 88 | 88 | ||
| 89 | explicit request(std::string url) try | 89 | explicit request(std::string url) try |
| 90 | : _ios(_output), _conn(_ios) | 90 | : _ios(_output), _conn(_ios) |
| 91 | { | 91 | { |
| @@ -93,10 +93,10 @@ namespace twitter { | |||
| 93 | } catch (const curl::curl_easy_exception& error) | 93 | } catch (const curl::curl_easy_exception& error) |
| 94 | { | 94 | { |
| 95 | error.print_traceback(); | 95 | error.print_traceback(); |
| 96 | 96 | ||
| 97 | assert(false); | 97 | assert(false); |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | std::string perform() | 100 | std::string perform() |
| 101 | { | 101 | { |
| 102 | try | 102 | try |
| @@ -106,14 +106,14 @@ namespace twitter { | |||
| 106 | { | 106 | { |
| 107 | std::throw_with_nested(connection_error()); | 107 | std::throw_with_nested(connection_error()); |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | int response_code = _conn.get_info<CURLINFO_RESPONSE_CODE>().get(); | 110 | int response_code = _conn.get_info<CURLINFO_RESPONSE_CODE>().get(); |
| 111 | std::string result = _output.str(); | 111 | std::string result = _output.str(); |
| 112 | 112 | ||
| 113 | if (response_code / 100 != 2) | 113 | if (response_code / 100 != 2) |
| 114 | { | 114 | { |
| 115 | nlohmann::json response_json; | 115 | nlohmann::json response_json; |
| 116 | 116 | ||
| 117 | try | 117 | try |
| 118 | { | 118 | { |
| 119 | response_json = nlohmann::json::parse(result); | 119 | response_json = nlohmann::json::parse(result); |
| @@ -121,12 +121,12 @@ namespace twitter { | |||
| 121 | { | 121 | { |
| 122 | std::throw_with_nested(invalid_response(result)); | 122 | std::throw_with_nested(invalid_response(result)); |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | for (nlohmann::json& error : response_json["errors"]) | 125 | for (nlohmann::json& error : response_json["errors"]) |
| 126 | { | 126 | { |
| 127 | int error_code; | 127 | int error_code; |
| 128 | std::string error_message; | 128 | std::string error_message; |
| 129 | 129 | ||
| 130 | try | 130 | try |
| 131 | { | 131 | { |
| 132 | error_code = error["code"].get<int>(); | 132 | error_code = error["code"].get<int>(); |
| @@ -135,44 +135,44 @@ namespace twitter { | |||
| 135 | { | 135 | { |
| 136 | std::throw_with_nested(invalid_response(result)); | 136 | std::throw_with_nested(invalid_response(result)); |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | switch (error_code) | 139 | switch (error_code) |
| 140 | { | 140 | { |
| 141 | case 32: | 141 | case 32: |
| 142 | case 135: | 142 | case 135: |
| 143 | case 215: | 143 | case 215: |
| 144 | throw bad_auth(error_message); | 144 | throw bad_auth(error_message); |
| 145 | 145 | ||
| 146 | case 44: | 146 | case 44: |
| 147 | throw invalid_media(error_message); | 147 | throw invalid_media(error_message); |
| 148 | 148 | ||
| 149 | case 64: | 149 | case 64: |
| 150 | throw account_suspended(error_message); | 150 | throw account_suspended(error_message); |
| 151 | 151 | ||
| 152 | case 88: | 152 | case 88: |
| 153 | throw rate_limit_exceeded(error_message); | 153 | throw rate_limit_exceeded(error_message); |
| 154 | 154 | ||
| 155 | case 89: | 155 | case 89: |
| 156 | throw bad_token(error_message); | 156 | throw bad_token(error_message); |
| 157 | 157 | ||
| 158 | case 130: | 158 | case 130: |
| 159 | throw server_overloaded(error_message); | 159 | throw server_overloaded(error_message); |
| 160 | 160 | ||
| 161 | case 131: | 161 | case 131: |
| 162 | throw server_error(error_message); | 162 | throw server_error(error_message); |
| 163 | 163 | ||
| 164 | case 185: | 164 | case 185: |
| 165 | throw update_limit_exceeded(error_message); | 165 | throw update_limit_exceeded(error_message); |
| 166 | 166 | ||
| 167 | case 186: | 167 | case 186: |
| 168 | throw bad_length(error_message); | 168 | throw bad_length(error_message); |
| 169 | 169 | ||
| 170 | case 187: | 170 | case 187: |
| 171 | throw duplicate_status(error_message); | 171 | throw duplicate_status(error_message); |
| 172 | 172 | ||
| 173 | case 226: | 173 | case 226: |
| 174 | throw suspected_spam(error_message); | 174 | throw suspected_spam(error_message); |
| 175 | 175 | ||
| 176 | case 261: | 176 | case 261: |
| 177 | throw write_restricted(error_message); | 177 | throw write_restricted(error_message); |
| 178 | } | 178 | } |
| @@ -194,27 +194,27 @@ namespace twitter { | |||
| 194 | { | 194 | { |
| 195 | throw server_timeout("HTTP 504 Gateway Timeout"); | 195 | throw server_timeout("HTTP 504 Gateway Timeout"); |
| 196 | } | 196 | } |
| 197 | 197 | ||
| 198 | throw unknown_error(response_code, result); | 198 | throw unknown_error(response_code, result); |
| 199 | } | 199 | } |
| 200 | 200 | ||
| 201 | return result; | 201 | return result; |
| 202 | } | 202 | } |
| 203 | 203 | ||
| 204 | private: | 204 | private: |
| 205 | 205 | ||
| 206 | std::ostringstream _output; | 206 | std::ostringstream _output; |
| 207 | curl::curl_ios<std::ostringstream> _ios; | 207 | curl::curl_ios<std::ostringstream> _ios; |
| 208 | 208 | ||
| 209 | protected: | 209 | protected: |
| 210 | 210 | ||
| 211 | curl::curl_easy _conn; | 211 | curl::curl_easy _conn; |
| 212 | }; | 212 | }; |
| 213 | 213 | ||
| 214 | class get : public request | 214 | class get : public request |
| 215 | { | 215 | { |
| 216 | public: | 216 | public: |
| 217 | 217 | ||
| 218 | get(const OAuth::Client& oauth_client, std::string url) try | 218 | get(const OAuth::Client& oauth_client, std::string url) try |
| 219 | : request(url) | 219 | : request(url) |
| 220 | { | 220 | { |
| @@ -223,31 +223,31 @@ namespace twitter { | |||
| 223 | { | 223 | { |
| 224 | _headers.add(std::move(oauth_header)); | 224 | _headers.add(std::move(oauth_header)); |
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | _conn.add<CURLOPT_HTTPHEADER>(_headers.get()); | 227 | _conn.add<CURLOPT_HTTPHEADER>(_headers.get()); |
| 228 | } catch (const OAuth::ParseError& error) | 228 | } catch (const OAuth::ParseError& error) |
| 229 | { | 229 | { |
| 230 | std::cout << "Error generating OAuth header:" << std::endl; | 230 | std::cout << "Error generating OAuth header:" << std::endl; |
| 231 | std::cout << error.what() << std::endl; | 231 | std::cout << error.what() << std::endl; |
| 232 | std::cout << "This is likely due to a malformed URL." << std::endl; | 232 | std::cout << "This is likely due to a malformed URL." << std::endl; |
| 233 | 233 | ||
| 234 | assert(false); | 234 | assert(false); |
| 235 | } catch (const curl::curl_easy_exception& error) | 235 | } catch (const curl::curl_easy_exception& error) |
| 236 | { | 236 | { |
| 237 | error.print_traceback(); | 237 | error.print_traceback(); |
| 238 | 238 | ||
| 239 | assert(false); | 239 | assert(false); |
| 240 | } | 240 | } |
| 241 | 241 | ||
| 242 | private: | 242 | private: |
| 243 | 243 | ||
| 244 | curl::curl_header _headers; | 244 | curl::curl_header _headers; |
| 245 | }; | 245 | }; |
| 246 | 246 | ||
| 247 | class post : public request | 247 | class post : public request |
| 248 | { | 248 | { |
| 249 | public: | 249 | public: |
| 250 | 250 | ||
| 251 | post(const OAuth::Client& oauth_client, std::string url, std::string datastr) try | 251 | post(const OAuth::Client& oauth_client, std::string url, std::string datastr) try |
| 252 | : request(url) | 252 | : request(url) |
| 253 | { | 253 | { |
| @@ -256,7 +256,7 @@ namespace twitter { | |||
| 256 | { | 256 | { |
| 257 | _headers.add(std::move(oauth_header)); | 257 | _headers.add(std::move(oauth_header)); |
| 258 | } | 258 | } |
| 259 | 259 | ||
| 260 | _conn.add<CURLOPT_HTTPHEADER>(_headers.get()); | 260 | _conn.add<CURLOPT_HTTPHEADER>(_headers.get()); |
| 261 | _conn.add<CURLOPT_COPYPOSTFIELDS>(datastr.c_str()); | 261 | _conn.add<CURLOPT_COPYPOSTFIELDS>(datastr.c_str()); |
| 262 | } catch (const OAuth::ParseError& error) | 262 | } catch (const OAuth::ParseError& error) |
| @@ -264,24 +264,24 @@ namespace twitter { | |||
| 264 | std::cout << "Error generating OAuth header:" << std::endl; | 264 | std::cout << "Error generating OAuth header:" << std::endl; |
| 265 | std::cout << error.what() << std::endl; | 265 | std::cout << error.what() << std::endl; |
| 266 | std::cout << "This is likely due to a malformed URL." << std::endl; | 266 | std::cout << "This is likely due to a malformed URL." << std::endl; |
| 267 | 267 | ||
| 268 | assert(false); | 268 | assert(false); |
| 269 | } catch (const curl::curl_easy_exception& error) | 269 | } catch (const curl::curl_easy_exception& error) |
| 270 | { | 270 | { |
| 271 | error.print_traceback(); | 271 | error.print_traceback(); |
| 272 | 272 | ||
| 273 | assert(false); | 273 | assert(false); |
| 274 | } | 274 | } |
| 275 | 275 | ||
| 276 | private: | 276 | private: |
| 277 | 277 | ||
| 278 | curl::curl_header _headers; | 278 | curl::curl_header _headers; |
| 279 | }; | 279 | }; |
| 280 | 280 | ||
| 281 | class multipost : public request | 281 | class multipost : public request |
| 282 | { | 282 | { |
| 283 | public: | 283 | public: |
| 284 | 284 | ||
| 285 | multipost(const OAuth::Client& oauth_client, std::string url, const curl_httppost* fields) try | 285 | multipost(const OAuth::Client& oauth_client, std::string url, const curl_httppost* fields) try |
| 286 | : request(url) | 286 | : request(url) |
| 287 | { | 287 | { |
| @@ -290,7 +290,7 @@ namespace twitter { | |||
| 290 | { | 290 | { |
| 291 | _headers.add(std::move(oauth_header)); | 291 | _headers.add(std::move(oauth_header)); |
| 292 | } | 292 | } |
| 293 | 293 | ||
| 294 | _conn.add<CURLOPT_HTTPHEADER>(_headers.get()); | 294 | _conn.add<CURLOPT_HTTPHEADER>(_headers.get()); |
| 295 | _conn.add<CURLOPT_HTTPPOST>(fields); | 295 | _conn.add<CURLOPT_HTTPPOST>(fields); |
| 296 | } catch (const OAuth::ParseError& error) | 296 | } catch (const OAuth::ParseError& error) |
| @@ -298,94 +298,94 @@ namespace twitter { | |||
| 298 | std::cout << "Error generating OAuth header:" << std::endl; | 298 | std::cout << "Error generating OAuth header:" << std::endl; |
| 299 | std::cout << error.what() << std::endl; | 299 | std::cout << error.what() << std::endl; |
| 300 | std::cout << "This is likely due to a malformed URL." << std::endl; | 300 | std::cout << "This is likely due to a malformed URL." << std::endl; |
| 301 | 301 | ||
| 302 | assert(false); | 302 | assert(false); |
| 303 | } catch (const curl::curl_easy_exception& error) | 303 | } catch (const curl::curl_easy_exception& error) |
| 304 | { | 304 | { |
| 305 | error.print_traceback(); | 305 | error.print_traceback(); |
| 306 | 306 | ||
| 307 | assert(false); | 307 | assert(false); |
| 308 | } | 308 | } |
| 309 | 309 | ||
| 310 | private: | 310 | private: |
| 311 | 311 | ||
| 312 | curl::curl_header _headers; | 312 | curl::curl_header _headers; |
| 313 | }; | 313 | }; |
| 314 | 314 | ||
| 315 | client::client(const auth& _arg) | 315 | client::client(const auth& _arg) |
| 316 | { | 316 | { |
| 317 | _oauth_consumer = | 317 | _oauth_consumer = |
| 318 | make_unique<OAuth::Consumer>( | 318 | make_unique<OAuth::Consumer>( |
| 319 | _arg.getConsumerKey(), | 319 | _arg.getConsumerKey(), |
| 320 | _arg.getConsumerSecret()); | 320 | _arg.getConsumerSecret()); |
| 321 | 321 | ||
| 322 | _oauth_token = | 322 | _oauth_token = |
| 323 | make_unique<OAuth::Token>( | 323 | make_unique<OAuth::Token>( |
| 324 | _arg.getAccessKey(), | 324 | _arg.getAccessKey(), |
| 325 | _arg.getAccessSecret()); | 325 | _arg.getAccessSecret()); |
| 326 | 326 | ||
| 327 | _oauth_client = | 327 | _oauth_client = |
| 328 | make_unique<OAuth::Client>( | 328 | make_unique<OAuth::Client>( |
| 329 | _oauth_consumer.get(), | 329 | _oauth_consumer.get(), |
| 330 | _oauth_token.get()); | 330 | _oauth_token.get()); |
| 331 | 331 | ||
| 332 | _current_user = | 332 | _current_user = |
| 333 | make_unique<user>( | 333 | make_unique<user>( |
| 334 | get(*_oauth_client, | 334 | get(*_oauth_client, |
| 335 | "https://api.twitter.com/1.1/account/verify_credentials.json") | 335 | "https://api.twitter.com/1.1/account/verify_credentials.json") |
| 336 | .perform()); | 336 | .perform()); |
| 337 | } | 337 | } |
| 338 | 338 | ||
| 339 | client::~client() = default; | 339 | client::~client() = default; |
| 340 | 340 | ||
| 341 | tweet client::updateStatus(std::string msg, std::list<long> media_ids) const | 341 | tweet client::updateStatus(std::string msg, std::list<long> media_ids) const |
| 342 | { | 342 | { |
| 343 | std::stringstream datastrstream; | 343 | std::stringstream datastrstream; |
| 344 | datastrstream << "status=" << OAuth::PercentEncode(msg); | 344 | datastrstream << "status=" << OAuth::PercentEncode(msg); |
| 345 | 345 | ||
| 346 | if (!media_ids.empty()) | 346 | if (!media_ids.empty()) |
| 347 | { | 347 | { |
| 348 | datastrstream << "&media_ids="; | 348 | datastrstream << "&media_ids="; |
| 349 | datastrstream << twitter::implode(std::begin(media_ids), std::end(media_ids), ","); | 349 | datastrstream << twitter::implode(std::begin(media_ids), std::end(media_ids), ","); |
| 350 | } | 350 | } |
| 351 | 351 | ||
| 352 | return tweet( | 352 | return tweet( |
| 353 | post(*_oauth_client, | 353 | post(*_oauth_client, |
| 354 | "https://api.twitter.com/1.1/statuses/update.json", | 354 | "https://api.twitter.com/1.1/statuses/update.json", |
| 355 | datastrstream.str()) | 355 | datastrstream.str()) |
| 356 | .perform()); | 356 | .perform()); |
| 357 | } | 357 | } |
| 358 | 358 | ||
| 359 | tweet client::replyToTweet(std::string msg, tweet_id in_response_to, std::list<long> media_ids) const | 359 | tweet client::replyToTweet(std::string msg, tweet_id in_response_to, std::list<long> media_ids) const |
| 360 | { | 360 | { |
| 361 | std::stringstream datastrstream; | 361 | std::stringstream datastrstream; |
| 362 | datastrstream << "status=" << OAuth::PercentEncode(msg); | 362 | datastrstream << "status=" << OAuth::PercentEncode(msg); |
| 363 | datastrstream << "&in_reply_to_status_id="; | 363 | datastrstream << "&in_reply_to_status_id="; |
| 364 | datastrstream << in_response_to; | 364 | datastrstream << in_response_to; |
| 365 | 365 | ||
| 366 | if (!media_ids.empty()) | 366 | if (!media_ids.empty()) |
| 367 | { | 367 | { |
| 368 | datastrstream << "&media_ids="; | 368 | datastrstream << "&media_ids="; |
| 369 | datastrstream << twitter::implode(std::begin(media_ids), std::end(media_ids), ","); | 369 | datastrstream << twitter::implode(std::begin(media_ids), std::end(media_ids), ","); |
| 370 | } | 370 | } |
| 371 | 371 | ||
| 372 | return tweet( | 372 | return tweet( |
| 373 | post(*_oauth_client, | 373 | post(*_oauth_client, |
| 374 | "https://api.twitter.com/1.1/statuses/update.json", | 374 | "https://api.twitter.com/1.1/statuses/update.json", |
| 375 | datastrstream.str()) | 375 | datastrstream.str()) |
| 376 | .perform()); | 376 | .perform()); |
| 377 | } | 377 | } |
| 378 | 378 | ||
| 379 | tweet client::replyToTweet(std::string msg, const tweet& in_response_to, std::list<long> media_ids) const | 379 | tweet client::replyToTweet(std::string msg, const tweet& in_response_to, std::list<long> media_ids) const |
| 380 | { | 380 | { |
| 381 | return replyToTweet(msg, in_response_to.getID(), media_ids); | 381 | return replyToTweet(msg, in_response_to.getID(), media_ids); |
| 382 | } | 382 | } |
| 383 | 383 | ||
| 384 | long client::uploadMedia(std::string media_type, const char* data, long data_length) const try | 384 | long client::uploadMedia(std::string media_type, const char* data, long data_length) const try |
| 385 | { | 385 | { |
| 386 | curl::curl_form form; | 386 | curl::curl_form form; |
| 387 | std::string str_data_length = std::to_string(data_length); | 387 | std::string str_data_length = std::to_string(data_length); |
| 388 | 388 | ||
| 389 | curl::curl_pair<CURLformoption, std::string> command_name(CURLFORM_COPYNAME, "command"); | 389 | curl::curl_pair<CURLformoption, std::string> command_name(CURLFORM_COPYNAME, "command"); |
| 390 | curl::curl_pair<CURLformoption, std::string> command_cont(CURLFORM_COPYCONTENTS, "INIT"); | 390 | curl::curl_pair<CURLformoption, std::string> command_cont(CURLFORM_COPYCONTENTS, "INIT"); |
| 391 | curl::curl_pair<CURLformoption, std::string> bytes_name(CURLFORM_COPYNAME, "total_bytes"); | 391 | curl::curl_pair<CURLformoption, std::string> bytes_name(CURLFORM_COPYNAME, "total_bytes"); |
| @@ -402,7 +402,7 @@ namespace twitter { | |||
| 402 | curl::curl_pair<CURLformoption, std::string> category_cont(CURLFORM_COPYCONTENTS, "tweet_gif"); | 402 | curl::curl_pair<CURLformoption, std::string> category_cont(CURLFORM_COPYCONTENTS, "tweet_gif"); |
| 403 | form.add(category_name, category_cont); | 403 | form.add(category_name, category_cont); |
| 404 | } | 404 | } |
| 405 | 405 | ||
| 406 | std::string init_response = | 406 | std::string init_response = |
| 407 | multipost(*_oauth_client, | 407 | multipost(*_oauth_client, |
| 408 | "https://upload.twitter.com/1.1/media/upload.json", | 408 | "https://upload.twitter.com/1.1/media/upload.json", |
| @@ -410,7 +410,7 @@ namespace twitter { | |||
| 410 | .perform(); | 410 | .perform(); |
| 411 | 411 | ||
| 412 | long media_id; | 412 | long media_id; |
| 413 | 413 | ||
| 414 | try | 414 | try |
| 415 | { | 415 | { |
| 416 | nlohmann::json response_json = nlohmann::json::parse(init_response); | 416 | nlohmann::json response_json = nlohmann::json::parse(init_response); |
| @@ -434,21 +434,21 @@ namespace twitter { | |||
| 434 | { | 434 | { |
| 435 | assert(false); | 435 | assert(false); |
| 436 | } | 436 | } |
| 437 | 437 | ||
| 438 | multipost(*_oauth_client, "https://upload.twitter.com/1.1/media/upload.json", append_form_post).perform(); | 438 | multipost(*_oauth_client, "https://upload.twitter.com/1.1/media/upload.json", append_form_post).perform(); |
| 439 | 439 | ||
| 440 | curl_formfree(append_form_post); | 440 | curl_formfree(append_form_post); |
| 441 | 441 | ||
| 442 | curl::curl_form finalize_form; | 442 | curl::curl_form finalize_form; |
| 443 | std::string str_media_id = std::to_string(media_id); | 443 | std::string str_media_id = std::to_string(media_id); |
| 444 | 444 | ||
| 445 | curl::curl_pair<CURLformoption, std::string> command3_name(CURLFORM_COPYNAME, "command"); | 445 | curl::curl_pair<CURLformoption, std::string> command3_name(CURLFORM_COPYNAME, "command"); |
| 446 | curl::curl_pair<CURLformoption, std::string> command3_cont(CURLFORM_COPYCONTENTS, "FINALIZE"); | 446 | curl::curl_pair<CURLformoption, std::string> command3_cont(CURLFORM_COPYCONTENTS, "FINALIZE"); |
| 447 | curl::curl_pair<CURLformoption, std::string> media_id_name(CURLFORM_COPYNAME, "media_id"); | 447 | curl::curl_pair<CURLformoption, std::string> media_id_name(CURLFORM_COPYNAME, "media_id"); |
| 448 | curl::curl_pair<CURLformoption, std::string> media_id_cont(CURLFORM_COPYCONTENTS, str_media_id); | 448 | curl::curl_pair<CURLformoption, std::string> media_id_cont(CURLFORM_COPYCONTENTS, str_media_id); |
| 449 | finalize_form.add(command3_name, command3_cont); | 449 | finalize_form.add(command3_name, command3_cont); |
| 450 | finalize_form.add(media_id_name, media_id_cont); | 450 | finalize_form.add(media_id_name, media_id_cont); |
| 451 | 451 | ||
| 452 | std::string finalize_response = | 452 | std::string finalize_response = |
| 453 | multipost(*_oauth_client, | 453 | multipost(*_oauth_client, |
| 454 | "https://upload.twitter.com/1.1/media/upload.json", | 454 | "https://upload.twitter.com/1.1/media/upload.json", |
| @@ -456,7 +456,7 @@ namespace twitter { | |||
| 456 | .perform(); | 456 | .perform(); |
| 457 | 457 | ||
| 458 | nlohmann::json finalize_json; | 458 | nlohmann::json finalize_json; |
| 459 | 459 | ||
| 460 | try | 460 | try |
| 461 | { | 461 | { |
| 462 | finalize_json = nlohmann::json::parse(finalize_response); | 462 | finalize_json = nlohmann::json::parse(finalize_response); |
| @@ -464,26 +464,26 @@ namespace twitter { | |||
| 464 | { | 464 | { |
| 465 | std::throw_with_nested(invalid_response(finalize_response)); | 465 | std::throw_with_nested(invalid_response(finalize_response)); |
| 466 | } | 466 | } |
| 467 | 467 | ||
| 468 | if (finalize_json.find("processing_info") != finalize_json.end()) | 468 | if (finalize_json.find("processing_info") != finalize_json.end()) |
| 469 | { | 469 | { |
| 470 | std::stringstream datastr; | 470 | std::stringstream datastr; |
| 471 | datastr << "https://upload.twitter.com/1.1/media/upload.json?command=STATUS&media_id=" << media_id; | 471 | datastr << "https://upload.twitter.com/1.1/media/upload.json?command=STATUS&media_id=" << media_id; |
| 472 | 472 | ||
| 473 | for (;;) | 473 | for (;;) |
| 474 | { | 474 | { |
| 475 | std::string status_response = get(*_oauth_client, datastr.str()).perform(); | 475 | std::string status_response = get(*_oauth_client, datastr.str()).perform(); |
| 476 | 476 | ||
| 477 | try | 477 | try |
| 478 | { | 478 | { |
| 479 | nlohmann::json status_json = nlohmann::json::parse(status_response); | 479 | nlohmann::json status_json = nlohmann::json::parse(status_response); |
| 480 | std::string state = status_json["processing_info"]["state"].get<std::string>(); | 480 | std::string state = status_json["processing_info"]["state"].get<std::string>(); |
| 481 | 481 | ||
| 482 | if (state == "succeeded") | 482 | if (state == "succeeded") |
| 483 | { | 483 | { |
| 484 | break; | 484 | break; |
| 485 | } | 485 | } |
| 486 | 486 | ||
| 487 | int ttw = status_json["processing_info"]["check_after_secs"].get<int>(); | 487 | int ttw = status_json["processing_info"]["check_after_secs"].get<int>(); |
| 488 | std::this_thread::sleep_for(std::chrono::seconds(ttw)); | 488 | std::this_thread::sleep_for(std::chrono::seconds(ttw)); |
| 489 | } catch (const std::invalid_argument& error) | 489 | } catch (const std::invalid_argument& error) |
| @@ -495,20 +495,20 @@ namespace twitter { | |||
| 495 | } | 495 | } |
| 496 | } | 496 | } |
| 497 | } | 497 | } |
| 498 | 498 | ||
| 499 | return media_id; | 499 | return media_id; |
| 500 | } catch (const curl::curl_exception& error) | 500 | } catch (const curl::curl_exception& error) |
| 501 | { | 501 | { |
| 502 | error.print_traceback(); | 502 | error.print_traceback(); |
| 503 | 503 | ||
| 504 | assert(false); | 504 | assert(false); |
| 505 | } | 505 | } |
| 506 | 506 | ||
| 507 | std::set<user_id> client::getFriends(user_id id) const | 507 | std::set<user_id> client::getFriends(user_id id) const |
| 508 | { | 508 | { |
| 509 | long long cursor = -1; | 509 | long long cursor = -1; |
| 510 | std::set<user_id> result; | 510 | std::set<user_id> result; |
| 511 | 511 | ||
| 512 | while (cursor != 0) | 512 | while (cursor != 0) |
| 513 | { | 513 | { |
| 514 | std::stringstream urlstream; | 514 | std::stringstream urlstream; |
| @@ -516,14 +516,14 @@ namespace twitter { | |||
| 516 | urlstream << id; | 516 | urlstream << id; |
| 517 | urlstream << "&cursor="; | 517 | urlstream << "&cursor="; |
| 518 | urlstream << cursor; | 518 | urlstream << cursor; |
| 519 | 519 | ||
| 520 | std::string url = urlstream.str(); | 520 | std::string url = urlstream.str(); |
| 521 | std::string response_data = get(*_oauth_client, url).perform(); | 521 | std::string response_data = get(*_oauth_client, url).perform(); |
| 522 | 522 | ||
| 523 | try | 523 | try |
| 524 | { | 524 | { |
| 525 | nlohmann::json rjs = nlohmann::json::parse(response_data); | 525 | nlohmann::json rjs = nlohmann::json::parse(response_data); |
| 526 | 526 | ||
| 527 | cursor = rjs["next_cursor"].get<long long>(); | 527 | cursor = rjs["next_cursor"].get<long long>(); |
| 528 | result.insert(std::begin(rjs["ids"]), std::end(rjs["ids"])); | 528 | result.insert(std::begin(rjs["ids"]), std::end(rjs["ids"])); |
| 529 | } catch (const std::invalid_argument& error) | 529 | } catch (const std::invalid_argument& error) |
| @@ -534,25 +534,25 @@ namespace twitter { | |||
| 534 | std::throw_with_nested(invalid_response(response_data)); | 534 | std::throw_with_nested(invalid_response(response_data)); |
| 535 | } | 535 | } |
| 536 | } | 536 | } |
| 537 | 537 | ||
| 538 | return result; | 538 | return result; |
| 539 | } | 539 | } |
| 540 | 540 | ||
| 541 | std::set<user_id> client::getFriends(const user& id) const | 541 | std::set<user_id> client::getFriends(const user& id) const |
| 542 | { | 542 | { |
| 543 | return getFriends(id.getID()); | 543 | return getFriends(id.getID()); |
| 544 | } | 544 | } |
| 545 | 545 | ||
| 546 | std::set<user_id> client::getFriends() const | 546 | std::set<user_id> client::getFriends() const |
| 547 | { | 547 | { |
| 548 | return getFriends(getUser().getID()); | 548 | return getFriends(getUser().getID()); |
| 549 | } | 549 | } |
| 550 | 550 | ||
| 551 | std::set<user_id> client::getFollowers(user_id id) const | 551 | std::set<user_id> client::getFollowers(user_id id) const |
| 552 | { | 552 | { |
| 553 | long long cursor = -1; | 553 | long long cursor = -1; |
| 554 | std::set<user_id> result; | 554 | std::set<user_id> result; |
| 555 | 555 | ||
| 556 | while (cursor != 0) | 556 | while (cursor != 0) |
| 557 | { | 557 | { |
| 558 | std::stringstream urlstream; | 558 | std::stringstream urlstream; |
| @@ -560,14 +560,14 @@ namespace twitter { | |||
| 560 | urlstream << id; | 560 | urlstream << id; |
| 561 | urlstream << "&cursor="; | 561 | urlstream << "&cursor="; |
| 562 | urlstream << cursor; | 562 | urlstream << cursor; |
| 563 | 563 | ||
| 564 | std::string url = urlstream.str(); | 564 | std::string url = urlstream.str(); |
| 565 | std::string response_data = get(*_oauth_client, url).perform(); | 565 | std::string response_data = get(*_oauth_client, url).perform(); |
| 566 | 566 | ||
| 567 | try | 567 | try |
| 568 | { | 568 | { |
| 569 | nlohmann::json rjs = nlohmann::json::parse(response_data); | 569 | nlohmann::json rjs = nlohmann::json::parse(response_data); |
| 570 | 570 | ||
| 571 | cursor = rjs["next_cursor"].get<long long>(); | 571 | cursor = rjs["next_cursor"].get<long long>(); |
| 572 | result.insert(std::begin(rjs["ids"]), std::end(rjs["ids"])); | 572 | result.insert(std::begin(rjs["ids"]), std::end(rjs["ids"])); |
| 573 | } catch (const std::invalid_argument& error) | 573 | } catch (const std::invalid_argument& error) |
| @@ -578,15 +578,15 @@ namespace twitter { | |||
| 578 | std::throw_with_nested(invalid_response(response_data)); | 578 | std::throw_with_nested(invalid_response(response_data)); |
| 579 | } | 579 | } |
| 580 | } | 580 | } |
| 581 | 581 | ||
| 582 | return result; | 582 | return result; |
| 583 | } | 583 | } |
| 584 | 584 | ||
| 585 | std::set<user_id> client::getFollowers(const user& id) const | 585 | std::set<user_id> client::getFollowers(const user& id) const |
| 586 | { | 586 | { |
| 587 | return getFollowers(id.getID()); | 587 | return getFollowers(id.getID()); |
| 588 | } | 588 | } |
| 589 | 589 | ||
| 590 | std::set<user_id> client::getFollowers() const | 590 | std::set<user_id> client::getFollowers() const |
| 591 | { | 591 | { |
| 592 | return getFollowers(getUser().getID()); | 592 | return getFollowers(getUser().getID()); |
| @@ -629,24 +629,24 @@ namespace twitter { | |||
| 629 | std::stringstream datastrstream; | 629 | std::stringstream datastrstream; |
| 630 | datastrstream << "follow=true&user_id="; | 630 | datastrstream << "follow=true&user_id="; |
| 631 | datastrstream << toFollow; | 631 | datastrstream << toFollow; |
| 632 | 632 | ||
| 633 | post(*_oauth_client, "https://api.twitter.com/1.1/friendships/create.json", datastrstream.str()).perform(); | 633 | post(*_oauth_client, "https://api.twitter.com/1.1/friendships/create.json", datastrstream.str()).perform(); |
| 634 | } | 634 | } |
| 635 | 635 | ||
| 636 | void client::follow(const user& toFollow) const | 636 | void client::follow(const user& toFollow) const |
| 637 | { | 637 | { |
| 638 | return follow(toFollow.getID()); | 638 | return follow(toFollow.getID()); |
| 639 | } | 639 | } |
| 640 | 640 | ||
| 641 | void client::unfollow(user_id toUnfollow) const | 641 | void client::unfollow(user_id toUnfollow) const |
| 642 | { | 642 | { |
| 643 | std::stringstream datastrstream; | 643 | std::stringstream datastrstream; |
| 644 | datastrstream << "user_id="; | 644 | datastrstream << "user_id="; |
| 645 | datastrstream << toUnfollow; | 645 | datastrstream << toUnfollow; |
| 646 | 646 | ||
| 647 | post(*_oauth_client, "https://api.twitter.com/1.1/friendships/destroy.json", datastrstream.str()).perform(); | 647 | post(*_oauth_client, "https://api.twitter.com/1.1/friendships/destroy.json", datastrstream.str()).perform(); |
| 648 | } | 648 | } |
| 649 | 649 | ||
| 650 | void client::unfollow(const user& toUnfollow) const | 650 | void client::unfollow(const user& toUnfollow) const |
| 651 | { | 651 | { |
| 652 | return unfollow(toUnfollow.getID()); | 652 | return unfollow(toUnfollow.getID()); |
| @@ -656,7 +656,7 @@ namespace twitter { | |||
| 656 | { | 656 | { |
| 657 | return *_current_user; | 657 | return *_current_user; |
| 658 | } | 658 | } |
| 659 | 659 | ||
| 660 | const configuration& client::getConfiguration() const | 660 | const configuration& client::getConfiguration() const |
| 661 | { | 661 | { |
| 662 | if (!_configuration || (difftime(time(NULL), _last_configuration_update) > 60*60*24)) | 662 | if (!_configuration || (difftime(time(NULL), _last_configuration_update) > 60*60*24)) |
| @@ -669,8 +669,8 @@ namespace twitter { | |||
| 669 | 669 | ||
| 670 | _last_configuration_update = time(NULL); | 670 | _last_configuration_update = time(NULL); |
| 671 | } | 671 | } |
| 672 | 672 | ||
| 673 | return *_configuration; | 673 | return *_configuration; |
| 674 | } | 674 | } |
| 675 | 675 | ||
| 676 | }; | 676 | }; |
| diff --git a/src/client.h b/src/client.h index 9282321..1e1b1ab 100644 --- a/src/client.h +++ b/src/client.h | |||
| @@ -18,23 +18,23 @@ namespace OAuth { | |||
| 18 | }; | 18 | }; |
| 19 | 19 | ||
| 20 | namespace twitter { | 20 | namespace twitter { |
| 21 | 21 | ||
| 22 | class client { | 22 | class client { |
| 23 | public: | 23 | public: |
| 24 | 24 | ||
| 25 | client(const auth& _auth); | 25 | client(const auth& _auth); |
| 26 | ~client(); | 26 | ~client(); |
| 27 | 27 | ||
| 28 | tweet updateStatus(std::string msg, std::list<long> media_ids = {}) const; | 28 | tweet updateStatus(std::string msg, std::list<long> media_ids = {}) const; |
| 29 | long uploadMedia(std::string media_type, const char* data, long data_length) const; | 29 | long uploadMedia(std::string media_type, const char* data, long data_length) const; |
| 30 | 30 | ||
| 31 | tweet replyToTweet(std::string msg, tweet_id in_response_to, std::list<long> media_ids = {}) const; | 31 | tweet replyToTweet(std::string msg, tweet_id in_response_to, std::list<long> media_ids = {}) const; |
| 32 | tweet replyToTweet(std::string msg, const tweet& in_response_to, std::list<long> media_ids = {}) const; | 32 | tweet replyToTweet(std::string msg, const tweet& in_response_to, std::list<long> media_ids = {}) const; |
| 33 | 33 | ||
| 34 | std::set<user_id> getFriends(user_id id) const; | 34 | std::set<user_id> getFriends(user_id id) const; |
| 35 | std::set<user_id> getFriends(const user& u) const; | 35 | std::set<user_id> getFriends(const user& u) const; |
| 36 | std::set<user_id> getFriends() const; | 36 | std::set<user_id> getFriends() const; |
| 37 | 37 | ||
| 38 | std::set<user_id> getFollowers(user_id id) const; | 38 | std::set<user_id> getFollowers(user_id id) const; |
| 39 | std::set<user_id> getFollowers(const user& u) const; | 39 | std::set<user_id> getFollowers(const user& u) const; |
| 40 | std::set<user_id> getFollowers() const; | 40 | std::set<user_id> getFollowers() const; |
| @@ -43,28 +43,28 @@ namespace twitter { | |||
| 43 | 43 | ||
| 44 | void follow(user_id toFollow) const; | 44 | void follow(user_id toFollow) const; |
| 45 | void follow(const user& toFollow) const; | 45 | void follow(const user& toFollow) const; |
| 46 | 46 | ||
| 47 | void unfollow(user_id toUnfollow) const; | 47 | void unfollow(user_id toUnfollow) const; |
| 48 | void unfollow(const user& toUnfollow) const; | 48 | void unfollow(const user& toUnfollow) const; |
| 49 | 49 | ||
| 50 | const user& getUser() const; | 50 | const user& getUser() const; |
| 51 | 51 | ||
| 52 | const configuration& getConfiguration() const; | 52 | const configuration& getConfiguration() const; |
| 53 | 53 | ||
| 54 | private: | 54 | private: |
| 55 | 55 | ||
| 56 | friend class stream; | 56 | friend class stream; |
| 57 | 57 | ||
| 58 | std::unique_ptr<OAuth::Consumer> _oauth_consumer; | 58 | std::unique_ptr<OAuth::Consumer> _oauth_consumer; |
| 59 | std::unique_ptr<OAuth::Token> _oauth_token; | 59 | std::unique_ptr<OAuth::Token> _oauth_token; |
| 60 | std::unique_ptr<OAuth::Client> _oauth_client; | 60 | std::unique_ptr<OAuth::Client> _oauth_client; |
| 61 | 61 | ||
| 62 | std::unique_ptr<user> _current_user; | 62 | std::unique_ptr<user> _current_user; |
| 63 | 63 | ||
| 64 | mutable std::unique_ptr<configuration> _configuration; | 64 | mutable std::unique_ptr<configuration> _configuration; |
| 65 | mutable time_t _last_configuration_update; | 65 | mutable time_t _last_configuration_update; |
| 66 | }; | 66 | }; |
| 67 | 67 | ||
| 68 | }; | 68 | }; |
| 69 | 69 | ||
| 70 | #endif /* end of include guard: TWITTER_H_ABFF6A12 */ | 70 | #endif /* end of include guard: TWITTER_H_ABFF6A12 */ |
