diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/auth.cpp | 45 | ||||
| -rw-r--r-- | src/auth.h | 44 | ||||
| -rw-r--r-- | src/client.cpp | 460 | ||||
| -rw-r--r-- | src/client.h | 66 | ||||
| -rw-r--r-- | src/notification.cpp | 460 | ||||
| -rw-r--r-- | src/notification.h | 58 | ||||
| -rw-r--r-- | src/request.cpp | 264 | ||||
| -rw-r--r-- | src/request.h | 73 | ||||
| -rw-r--r-- | src/stream.cpp | 98 | ||||
| -rw-r--r-- | src/stream.h | 34 | ||||
| -rw-r--r-- | src/timeline.cpp | 82 | ||||
| -rw-r--r-- | src/timeline.h | 31 | ||||
| -rw-r--r-- | src/tweet.cpp | 8 | ||||
| -rw-r--r-- | src/twitter.h | 1 | ||||
| -rw-r--r-- | src/util.h | 16 |
15 files changed, 920 insertions, 820 deletions
| diff --git a/src/auth.cpp b/src/auth.cpp deleted file mode 100644 index f0f17e0..0000000 --- a/src/auth.cpp +++ /dev/null | |||
| @@ -1,45 +0,0 @@ | |||
| 1 | #include "auth.h" | ||
| 2 | |||
| 3 | namespace twitter { | ||
| 4 | |||
| 5 | void auth::setConsumerKey(std::string _arg) | ||
| 6 | { | ||
| 7 | _consumer_key = _arg; | ||
| 8 | } | ||
| 9 | |||
| 10 | void auth::setConsumerSecret(std::string _arg) | ||
| 11 | { | ||
| 12 | _consumer_secret = _arg; | ||
| 13 | } | ||
| 14 | |||
| 15 | void auth::setAccessKey(std::string _arg) | ||
| 16 | { | ||
| 17 | _access_key = _arg; | ||
| 18 | } | ||
| 19 | |||
| 20 | void auth::setAccessSecret(std::string _arg) | ||
| 21 | { | ||
| 22 | _access_secret = _arg; | ||
| 23 | } | ||
| 24 | |||
| 25 | std::string auth::getConsumerKey() const | ||
| 26 | { | ||
| 27 | return _consumer_key; | ||
| 28 | } | ||
| 29 | |||
| 30 | std::string auth::getConsumerSecret() const | ||
| 31 | { | ||
| 32 | return _consumer_secret; | ||
| 33 | } | ||
| 34 | |||
| 35 | std::string auth::getAccessKey() const | ||
| 36 | { | ||
| 37 | return _access_key; | ||
| 38 | } | ||
| 39 | |||
| 40 | std::string auth::getAccessSecret() const | ||
| 41 | { | ||
| 42 | return _access_secret; | ||
| 43 | } | ||
| 44 | |||
| 45 | }; | ||
| diff --git a/src/auth.h b/src/auth.h index ef07e81..30c178c 100644 --- a/src/auth.h +++ b/src/auth.h | |||
| @@ -2,28 +2,36 @@ | |||
| 2 | #define AUTH_H_48EF85FD | 2 | #define AUTH_H_48EF85FD |
| 3 | 3 | ||
| 4 | #include <string> | 4 | #include <string> |
| 5 | #include "../vendor/liboauthcpp/include/liboauthcpp/liboauthcpp.h" | ||
| 5 | 6 | ||
| 6 | namespace twitter { | 7 | namespace twitter { |
| 7 | 8 | ||
| 8 | class auth { | 9 | class auth { |
| 9 | public: | 10 | public: |
| 10 | void setConsumerKey(std::string _arg); | 11 | |
| 11 | void setConsumerSecret(std::string _arg); | 12 | auth( |
| 12 | void setAccessKey(std::string _arg); | 13 | std::string consumerKey, |
| 13 | void setAccessSecret(std::string _arg); | 14 | std::string consumerSecret, |
| 14 | 15 | std::string accessKey, | |
| 15 | std::string getConsumerKey() const; | 16 | std::string accessSecret) : |
| 16 | std::string getConsumerSecret() const; | 17 | consumer_(std::move(consumerKey), std::move(consumerSecret)), |
| 17 | std::string getAccessKey() const; | 18 | token_(std::move(accessKey), std::move(accessSecret)), |
| 18 | std::string getAccessSecret() const; | 19 | client_(&consumer_, &token_) |
| 19 | 20 | { | |
| 20 | private: | 21 | } |
| 21 | std::string _consumer_key; | 22 | |
| 22 | std::string _consumer_secret; | 23 | const OAuth::Client& getClient() const |
| 23 | std::string _access_key; | 24 | { |
| 24 | std::string _access_secret; | 25 | return client_; |
| 26 | } | ||
| 27 | |||
| 28 | private: | ||
| 29 | |||
| 30 | OAuth::Consumer consumer_; | ||
| 31 | OAuth::Token token_; | ||
| 32 | OAuth::Client client_; | ||
| 25 | }; | 33 | }; |
| 26 | 34 | ||
| 27 | }; | 35 | }; |
| 28 | 36 | ||
| 29 | #endif /* end of include guard: AUTH_H_48EF85FD */ | 37 | #endif /* end of include guard: AUTH_H_48EF85FD */ |
| 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 | }; |
| diff --git a/src/client.h b/src/client.h index 2230dbb..c0a63eb 100644 --- a/src/client.h +++ b/src/client.h | |||
| @@ -10,58 +10,66 @@ | |||
| 10 | #include "auth.h" | 10 | #include "auth.h" |
| 11 | #include "configuration.h" | 11 | #include "configuration.h" |
| 12 | #include "util.h" | 12 | #include "util.h" |
| 13 | 13 | #include "timeline.h" | |
| 14 | namespace OAuth { | ||
| 15 | class Consumer; | ||
| 16 | class Token; | ||
| 17 | class Client; | ||
| 18 | }; | ||
| 19 | 14 | ||
| 20 | namespace twitter { | 15 | namespace twitter { |
| 21 | 16 | ||
| 22 | class client { | 17 | class client { |
| 23 | public: | 18 | public: |
| 24 | 19 | ||
| 25 | client(const auth& _auth); | 20 | client(const auth& arg); |
| 26 | ~client(); | 21 | |
| 27 | |||
| 28 | tweet updateStatus(std::string msg, std::list<long> media_ids = {}) const; | 22 | 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; | 23 | long uploadMedia(std::string media_type, const char* data, long data_length) const; |
| 30 | 24 | ||
| 31 | tweet replyToTweet(std::string msg, tweet_id in_response_to, std::list<long> media_ids = {}) const; | 25 | tweet replyToTweet(std::string msg, tweet_id in_response_to, std::list<long> media_ids = {}) const; |
| 32 | 26 | ||
| 33 | std::set<user_id> getFriends(user_id id) const; | 27 | std::set<user_id> getFriends(user_id id) const; |
| 34 | std::set<user_id> getFriends(const user& u) const; | 28 | std::set<user_id> getFriends(const user& u) const; |
| 35 | std::set<user_id> getFriends() const; | 29 | std::set<user_id> getFriends() const; |
| 36 | 30 | ||
| 37 | std::set<user_id> getFollowers(user_id id) const; | 31 | std::set<user_id> getFollowers(user_id id) const; |
| 38 | std::set<user_id> getFollowers(const user& u) const; | 32 | std::set<user_id> getFollowers(const user& u) const; |
| 39 | std::set<user_id> getFollowers() const; | 33 | std::set<user_id> getFollowers() const; |
| 40 | 34 | ||
| 41 | void follow(user_id toFollow) const; | 35 | void follow(user_id toFollow) const; |
| 42 | void follow(const user& toFollow) const; | 36 | void follow(const user& toFollow) const; |
| 43 | 37 | ||
| 44 | void unfollow(user_id toUnfollow) const; | 38 | void unfollow(user_id toUnfollow) const; |
| 45 | void unfollow(const user& toUnfollow) const; | 39 | void unfollow(const user& toUnfollow) const; |
| 46 | 40 | ||
| 47 | const user& getUser() const; | 41 | const user& getUser() const; |
| 48 | 42 | ||
| 49 | const configuration& getConfiguration() const; | 43 | const configuration& getConfiguration() const; |
| 50 | 44 | ||
| 45 | timeline& getHomeTimeline() | ||
| 46 | { | ||
| 47 | return homeTimeline_; | ||
| 48 | } | ||
| 49 | |||
| 50 | timeline& getMentionsTimeline() | ||
| 51 | { | ||
| 52 | return mentionsTimeline_; | ||
| 53 | } | ||
| 54 | |||
| 51 | private: | 55 | private: |
| 52 | 56 | ||
| 53 | friend class stream; | 57 | const auth& auth_; |
| 54 | 58 | ||
| 55 | std::unique_ptr<OAuth::Consumer> _oauth_consumer; | 59 | user currentUser_; |
| 56 | std::unique_ptr<OAuth::Token> _oauth_token; | 60 | |
| 57 | std::unique_ptr<OAuth::Client> _oauth_client; | ||
| 58 | |||
| 59 | std::unique_ptr<user> _current_user; | ||
| 60 | |||
| 61 | mutable std::unique_ptr<configuration> _configuration; | 61 | mutable std::unique_ptr<configuration> _configuration; |
| 62 | mutable time_t _last_configuration_update; | 62 | mutable time_t _last_configuration_update; |
| 63 | |||
| 64 | timeline homeTimeline_ { | ||
| 65 | auth_, | ||
| 66 | "https://api.twitter.com/1.1/statuses/home_timeline.json"}; | ||
| 67 | |||
| 68 | timeline mentionsTimeline_ { | ||
| 69 | auth_, | ||
| 70 | "https://api.twitter.com/1.1/statuses/mentions_timeline.json"}; | ||
| 63 | }; | 71 | }; |
| 64 | 72 | ||
| 65 | }; | 73 | }; |
| 66 | 74 | ||
| 67 | #endif /* end of include guard: TWITTER_H_ABFF6A12 */ | 75 | #endif /* end of include guard: TWITTER_H_ABFF6A12 */ |
| diff --git a/src/notification.cpp b/src/notification.cpp index 0e46112..0d09fcf 100644 --- a/src/notification.cpp +++ b/src/notification.cpp | |||
| @@ -6,18 +6,16 @@ | |||
| 6 | #include "client.h" | 6 | #include "client.h" |
| 7 | 7 | ||
| 8 | namespace twitter { | 8 | namespace twitter { |
| 9 | 9 | ||
| 10 | notification::type notification::getType() const | 10 | notification::type notification::getType() const |
| 11 | { | 11 | { |
| 12 | return _type; | 12 | return _type; |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | notification::notification(const client& tclient, std::string data) | 15 | notification::notification(const user& current_user, std::string data) |
| 16 | { | 16 | { |
| 17 | const user& current_user = tclient.getUser(); | ||
| 18 | |||
| 19 | nlohmann::json json; | 17 | nlohmann::json json; |
| 20 | 18 | ||
| 21 | try | 19 | try |
| 22 | { | 20 | { |
| 23 | json = nlohmann::json::parse(data); | 21 | json = nlohmann::json::parse(data); |
| @@ -25,7 +23,7 @@ namespace twitter { | |||
| 25 | { | 23 | { |
| 26 | std::throw_with_nested(invalid_response(data)); | 24 | std::throw_with_nested(invalid_response(data)); |
| 27 | } | 25 | } |
| 28 | 26 | ||
| 29 | try | 27 | try |
| 30 | { | 28 | { |
| 31 | if (!json["event"].is_null()) | 29 | if (!json["event"].is_null()) |
| @@ -33,48 +31,48 @@ namespace twitter { | |||
| 33 | std::string event = json["event"]; | 31 | std::string event = json["event"]; |
| 34 | user source(json["source"].dump()); | 32 | user source(json["source"].dump()); |
| 35 | user target(json["target"].dump()); | 33 | user target(json["target"].dump()); |
| 36 | 34 | ||
| 37 | if (event == "user_update") | 35 | if (event == "user_update") |
| 38 | { | 36 | { |
| 39 | _type = type::update_user; | 37 | _type = type::update_user; |
| 40 | 38 | ||
| 41 | new(&_user) user(source); | 39 | new(&_user) user(source); |
| 42 | } else if (event == "block") | 40 | } else if (event == "block") |
| 43 | { | 41 | { |
| 44 | _type = type::block; | 42 | _type = type::block; |
| 45 | 43 | ||
| 46 | new(&_user) user(target); | 44 | new(&_user) user(target); |
| 47 | } else if (event == "unblock") | 45 | } else if (event == "unblock") |
| 48 | { | 46 | { |
| 49 | _type = type::unblock; | 47 | _type = type::unblock; |
| 50 | 48 | ||
| 51 | new(&_user) user(target); | 49 | new(&_user) user(target); |
| 52 | } else if (event == "favorite") | 50 | } else if (event == "favorite") |
| 53 | { | 51 | { |
| 54 | new(&_user_and_tweet._tweet) tweet(json["target_object"].dump()); | 52 | new(&_user_and_tweet._tweet) tweet(json["target_object"].dump()); |
| 55 | 53 | ||
| 56 | if (current_user == source) | 54 | if (current_user == source) |
| 57 | { | 55 | { |
| 58 | _type = type::favorite; | 56 | _type = type::favorite; |
| 59 | 57 | ||
| 60 | new(&_user_and_tweet._user) user(target); | 58 | new(&_user_and_tweet._user) user(target); |
| 61 | } else { | 59 | } else { |
| 62 | _type = type::favorited; | 60 | _type = type::favorited; |
| 63 | 61 | ||
| 64 | new(&_user_and_tweet._user) user(source); | 62 | new(&_user_and_tweet._user) user(source); |
| 65 | } | 63 | } |
| 66 | } else if (event == "unfavorite") | 64 | } else if (event == "unfavorite") |
| 67 | { | 65 | { |
| 68 | new(&_user_and_tweet._tweet) tweet(json["target_object"].dump()); | 66 | new(&_user_and_tweet._tweet) tweet(json["target_object"].dump()); |
| 69 | 67 | ||
| 70 | if (current_user == source) | 68 | if (current_user == source) |
| 71 | { | 69 | { |
| 72 | _type = type::unfavorite; | 70 | _type = type::unfavorite; |
| 73 | 71 | ||
| 74 | new(&_user_and_tweet._user) user(target); | 72 | new(&_user_and_tweet._user) user(target); |
| 75 | } else { | 73 | } else { |
| 76 | _type = type::unfavorited; | 74 | _type = type::unfavorited; |
| 77 | 75 | ||
| 78 | new(&_user_and_tweet._user) user(source); | 76 | new(&_user_and_tweet._user) user(source); |
| 79 | } | 77 | } |
| 80 | } else if (event == "follow") | 78 | } else if (event == "follow") |
| @@ -82,93 +80,93 @@ namespace twitter { | |||
| 82 | if (current_user == source) | 80 | if (current_user == source) |
| 83 | { | 81 | { |
| 84 | _type = type::follow; | 82 | _type = type::follow; |
| 85 | 83 | ||
| 86 | new(&_user) user(target); | 84 | new(&_user) user(target); |
| 87 | } else { | 85 | } else { |
| 88 | _type = type::followed; | 86 | _type = type::followed; |
| 89 | 87 | ||
| 90 | new(&_user) user(source); | 88 | new(&_user) user(source); |
| 91 | } | 89 | } |
| 92 | } else if (event == "unfollow") | 90 | } else if (event == "unfollow") |
| 93 | { | 91 | { |
| 94 | _type = type::unfollow; | 92 | _type = type::unfollow; |
| 95 | 93 | ||
| 96 | new(&_user) user(target); | 94 | new(&_user) user(target); |
| 97 | } else if (event == "list_created") | 95 | } else if (event == "list_created") |
| 98 | { | 96 | { |
| 99 | _type = type::list_created; | 97 | _type = type::list_created; |
| 100 | 98 | ||
| 101 | new(&_list) list(json["target_object"].dump()); | 99 | new(&_list) list(json["target_object"].dump()); |
| 102 | } else if (event == "list_destroyed") | 100 | } else if (event == "list_destroyed") |
| 103 | { | 101 | { |
| 104 | _type = type::list_destroyed; | 102 | _type = type::list_destroyed; |
| 105 | 103 | ||
| 106 | new(&_list) list(json["target_object"].dump()); | 104 | new(&_list) list(json["target_object"].dump()); |
| 107 | } else if (event == "list_updated") | 105 | } else if (event == "list_updated") |
| 108 | { | 106 | { |
| 109 | _type = type::list_updated; | 107 | _type = type::list_updated; |
| 110 | 108 | ||
| 111 | new(&_list) list(json["target_object"].dump()); | 109 | new(&_list) list(json["target_object"].dump()); |
| 112 | } else if (event == "list_member_added") | 110 | } else if (event == "list_member_added") |
| 113 | { | 111 | { |
| 114 | new(&_user_and_list._list) list(json["target_object"].dump()); | 112 | new(&_user_and_list._list) list(json["target_object"].dump()); |
| 115 | 113 | ||
| 116 | if (current_user == source) | 114 | if (current_user == source) |
| 117 | { | 115 | { |
| 118 | _type = type::list_add; | 116 | _type = type::list_add; |
| 119 | 117 | ||
| 120 | new(&_user_and_list._user) user(target); | 118 | new(&_user_and_list._user) user(target); |
| 121 | } else { | 119 | } else { |
| 122 | _type = type::list_added; | 120 | _type = type::list_added; |
| 123 | 121 | ||
| 124 | new(&_user_and_list._user) user(source); | 122 | new(&_user_and_list._user) user(source); |
| 125 | } | 123 | } |
| 126 | } else if (event == "list_member_removed") | 124 | } else if (event == "list_member_removed") |
| 127 | { | 125 | { |
| 128 | new(&_user_and_list._list) list(json["target_object"].dump()); | 126 | new(&_user_and_list._list) list(json["target_object"].dump()); |
| 129 | 127 | ||
| 130 | if (current_user == source) | 128 | if (current_user == source) |
| 131 | { | 129 | { |
| 132 | _type = type::list_remove; | 130 | _type = type::list_remove; |
| 133 | 131 | ||
| 134 | new(&_user_and_list._user) user(target); | 132 | new(&_user_and_list._user) user(target); |
| 135 | } else { | 133 | } else { |
| 136 | _type = type::list_removed; | 134 | _type = type::list_removed; |
| 137 | 135 | ||
| 138 | new(&_user_and_list._user) user(source); | 136 | new(&_user_and_list._user) user(source); |
| 139 | } | 137 | } |
| 140 | } else if (event == "list_member_subscribe") | 138 | } else if (event == "list_member_subscribe") |
| 141 | { | 139 | { |
| 142 | new(&_user_and_list._list) list(json["target_object"].dump()); | 140 | new(&_user_and_list._list) list(json["target_object"].dump()); |
| 143 | 141 | ||
| 144 | if (current_user == source) | 142 | if (current_user == source) |
| 145 | { | 143 | { |
| 146 | _type = type::list_subscribe; | 144 | _type = type::list_subscribe; |
| 147 | 145 | ||
| 148 | new(&_user_and_list._user) user(target); | 146 | new(&_user_and_list._user) user(target); |
| 149 | } else { | 147 | } else { |
| 150 | _type = type::list_subscribed; | 148 | _type = type::list_subscribed; |
| 151 | 149 | ||
| 152 | new(&_user_and_list._user) user(source); | 150 | new(&_user_and_list._user) user(source); |
| 153 | } | 151 | } |
| 154 | } else if (event == "list_member_unsubscribe") | 152 | } else if (event == "list_member_unsubscribe") |
| 155 | { | 153 | { |
| 156 | new(&_user_and_list._list) list(json["target_object"].dump()); | 154 | new(&_user_and_list._list) list(json["target_object"].dump()); |
| 157 | 155 | ||
| 158 | if (current_user == source) | 156 | if (current_user == source) |
| 159 | { | 157 | { |
| 160 | _type = type::list_unsubscribe; | 158 | _type = type::list_unsubscribe; |
| 161 | 159 | ||
| 162 | new(&_user_and_list._user) user(target); | 160 | new(&_user_and_list._user) user(target); |
| 163 | } else { | 161 | } else { |
| 164 | _type = type::list_unsubscribed; | 162 | _type = type::list_unsubscribed; |
| 165 | 163 | ||
| 166 | new(&_user_and_list._user) user(source); | 164 | new(&_user_and_list._user) user(source); |
| 167 | } | 165 | } |
| 168 | } else if (event == "quoted_tweet") | 166 | } else if (event == "quoted_tweet") |
| 169 | { | 167 | { |
| 170 | _type = type::quoted; | 168 | _type = type::quoted; |
| 171 | 169 | ||
| 172 | new(&_user_and_tweet._user) user(source); | 170 | new(&_user_and_tweet._user) user(source); |
| 173 | new(&_user_and_tweet._tweet) tweet(json["target_object"].dump()); | 171 | new(&_user_and_tweet._tweet) tweet(json["target_object"].dump()); |
| 174 | } else { | 172 | } else { |
| @@ -177,7 +175,7 @@ namespace twitter { | |||
| 177 | } else if (!json["warning"].is_null()) | 175 | } else if (!json["warning"].is_null()) |
| 178 | { | 176 | { |
| 179 | new(&_warning) std::string(json["warning"]["message"].get<std::string>()); | 177 | new(&_warning) std::string(json["warning"]["message"].get<std::string>()); |
| 180 | 178 | ||
| 181 | auto warning_code = json["warning"]["code"].get<std::string>(); | 179 | auto warning_code = json["warning"]["code"].get<std::string>(); |
| 182 | if (warning_code == "FALLING_BEHIND") | 180 | if (warning_code == "FALLING_BEHIND") |
| 183 | { | 181 | { |
| @@ -191,27 +189,27 @@ namespace twitter { | |||
| 191 | } else if (!json["delete"].is_null()) | 189 | } else if (!json["delete"].is_null()) |
| 192 | { | 190 | { |
| 193 | _type = type::deletion; | 191 | _type = type::deletion; |
| 194 | 192 | ||
| 195 | _user_id_and_tweet_id._tweet_id = json["delete"]["status"]["id"].get<tweet_id>(); | 193 | _user_id_and_tweet_id._tweet_id = json["delete"]["status"]["id"].get<tweet_id>(); |
| 196 | _user_id_and_tweet_id._user_id = json["delete"]["status"]["user_id"].get<user_id>(); | 194 | _user_id_and_tweet_id._user_id = json["delete"]["status"]["user_id"].get<user_id>(); |
| 197 | } else if (!json["scrub_geo"].is_null()) | 195 | } else if (!json["scrub_geo"].is_null()) |
| 198 | { | 196 | { |
| 199 | _type = type::scrub_location; | 197 | _type = type::scrub_location; |
| 200 | 198 | ||
| 201 | _user_id_and_tweet_id._tweet_id = json["scrub_geo"]["up_to_status_id"].get<tweet_id>(); | 199 | _user_id_and_tweet_id._tweet_id = json["scrub_geo"]["up_to_status_id"].get<tweet_id>(); |
| 202 | _user_id_and_tweet_id._user_id = json["scrub_geo"]["user_id"].get<user_id>(); | 200 | _user_id_and_tweet_id._user_id = json["scrub_geo"]["user_id"].get<user_id>(); |
| 203 | } else if (!json["limit"].is_null()) | 201 | } else if (!json["limit"].is_null()) |
| 204 | { | 202 | { |
| 205 | _type = type::limit; | 203 | _type = type::limit; |
| 206 | 204 | ||
| 207 | _limit = json["limit"]["track"].get<int>(); | 205 | _limit = json["limit"]["track"].get<int>(); |
| 208 | } else if (!json["status_withheld"].is_null()) | 206 | } else if (!json["status_withheld"].is_null()) |
| 209 | { | 207 | { |
| 210 | _type = type::withhold_status; | 208 | _type = type::withhold_status; |
| 211 | 209 | ||
| 212 | _withhold_status._user_id = json["status_withheld"]["user_id"].get<user_id>(); | 210 | _withhold_status._user_id = json["status_withheld"]["user_id"].get<user_id>(); |
| 213 | _withhold_status._tweet_id = json["status_withheld"]["id"].get<tweet_id>(); | 211 | _withhold_status._tweet_id = json["status_withheld"]["id"].get<tweet_id>(); |
| 214 | 212 | ||
| 215 | new(&_withhold_status._countries) std::vector<std::string>(); | 213 | new(&_withhold_status._countries) std::vector<std::string>(); |
| 216 | for (auto s : json["status_withheld"]["withheld_in_countries"]) | 214 | for (auto s : json["status_withheld"]["withheld_in_countries"]) |
| 217 | { | 215 | { |
| @@ -220,9 +218,9 @@ namespace twitter { | |||
| 220 | } else if (!json["user_withheld"].is_null()) | 218 | } else if (!json["user_withheld"].is_null()) |
| 221 | { | 219 | { |
| 222 | _type = type::withhold_user; | 220 | _type = type::withhold_user; |
| 223 | 221 | ||
| 224 | _withhold_user._user_id = json["user_withheld"]["id"].get<user_id>(); | 222 | _withhold_user._user_id = json["user_withheld"]["id"].get<user_id>(); |
| 225 | 223 | ||
| 226 | new(&_withhold_user._countries) std::vector<std::string>(); | 224 | new(&_withhold_user._countries) std::vector<std::string>(); |
| 227 | for (auto s : json["user_withheld"]["withheld_in_countries"]) | 225 | for (auto s : json["user_withheld"]["withheld_in_countries"]) |
| 228 | { | 226 | { |
| @@ -231,7 +229,7 @@ namespace twitter { | |||
| 231 | } else if (!json["disconnect"].is_null()) | 229 | } else if (!json["disconnect"].is_null()) |
| 232 | { | 230 | { |
| 233 | _type = type::disconnect; | 231 | _type = type::disconnect; |
| 234 | 232 | ||
| 235 | switch (json["disconnect"]["code"].get<int>()) | 233 | switch (json["disconnect"]["code"].get<int>()) |
| 236 | { | 234 | { |
| 237 | case 1: _disconnect = disconnect_code::shutdown; break; | 235 | case 1: _disconnect = disconnect_code::shutdown; break; |
| @@ -249,16 +247,16 @@ namespace twitter { | |||
| 249 | } else if (!json["friends"].is_null()) | 247 | } else if (!json["friends"].is_null()) |
| 250 | { | 248 | { |
| 251 | _type = type::friends; | 249 | _type = type::friends; |
| 252 | 250 | ||
| 253 | new(&_friends) std::set<user_id>(std::begin(json["friends"]), std::end(json["friends"])); | 251 | new(&_friends) std::set<user_id>(std::begin(json["friends"]), std::end(json["friends"])); |
| 254 | } else if (!json["direct_message"].is_null()) | 252 | } else if (!json["direct_message"].is_null()) |
| 255 | { | 253 | { |
| 256 | _type = type::direct; | 254 | _type = type::direct; |
| 257 | 255 | ||
| 258 | new(&_direct_message) direct_message(json["direct_message"].dump()); | 256 | new(&_direct_message) direct_message(json["direct_message"].dump()); |
| 259 | } else { | 257 | } else { |
| 260 | _type = type::tweet; | 258 | _type = type::tweet; |
| 261 | 259 | ||
| 262 | new(&_tweet) tweet(data); | 260 | new(&_tweet) tweet(data); |
| 263 | } | 261 | } |
| 264 | } catch (const std::domain_error& error) | 262 | } catch (const std::domain_error& error) |
| @@ -266,20 +264,20 @@ namespace twitter { | |||
| 266 | std::throw_with_nested(invalid_response(data)); | 264 | std::throw_with_nested(invalid_response(data)); |
| 267 | } | 265 | } |
| 268 | } | 266 | } |
| 269 | 267 | ||
| 270 | notification::notification(const notification& other) | 268 | notification::notification(const notification& other) |
| 271 | { | 269 | { |
| 272 | _type = other._type; | 270 | _type = other._type; |
| 273 | 271 | ||
| 274 | switch (_type) | 272 | switch (_type) |
| 275 | { | 273 | { |
| 276 | case type::tweet: | 274 | case type::tweet: |
| 277 | { | 275 | { |
| 278 | new(&_tweet) tweet(other._tweet); | 276 | new(&_tweet) tweet(other._tweet); |
| 279 | 277 | ||
| 280 | break; | 278 | break; |
| 281 | } | 279 | } |
| 282 | 280 | ||
| 283 | case type::update_user: | 281 | case type::update_user: |
| 284 | case type::block: | 282 | case type::block: |
| 285 | case type::unblock: | 283 | case type::unblock: |
| @@ -288,10 +286,10 @@ namespace twitter { | |||
| 288 | case type::unfollow: | 286 | case type::unfollow: |
| 289 | { | 287 | { |
| 290 | new(&_user) user(other._user); | 288 | new(&_user) user(other._user); |
| 291 | 289 | ||
| 292 | break; | 290 | break; |
| 293 | } | 291 | } |
| 294 | 292 | ||
| 295 | case type::favorite: | 293 | case type::favorite: |
| 296 | case type::favorited: | 294 | case type::favorited: |
| 297 | case type::unfavorite: | 295 | case type::unfavorite: |
| @@ -300,19 +298,19 @@ namespace twitter { | |||
| 300 | { | 298 | { |
| 301 | new(&_user_and_tweet._user) user(other._user_and_tweet._user); | 299 | new(&_user_and_tweet._user) user(other._user_and_tweet._user); |
| 302 | new(&_user_and_tweet._tweet) tweet(other._user_and_tweet._tweet); | 300 | new(&_user_and_tweet._tweet) tweet(other._user_and_tweet._tweet); |
| 303 | 301 | ||
| 304 | break; | 302 | break; |
| 305 | } | 303 | } |
| 306 | 304 | ||
| 307 | case type::list_created: | 305 | case type::list_created: |
| 308 | case type::list_destroyed: | 306 | case type::list_destroyed: |
| 309 | case type::list_updated: | 307 | case type::list_updated: |
| 310 | { | 308 | { |
| 311 | new(&_list) list(other._list); | 309 | new(&_list) list(other._list); |
| 312 | 310 | ||
| 313 | break; | 311 | break; |
| 314 | } | 312 | } |
| 315 | 313 | ||
| 316 | case type::list_add: | 314 | case type::list_add: |
| 317 | case type::list_added: | 315 | case type::list_added: |
| 318 | case type::list_remove: | 316 | case type::list_remove: |
| @@ -324,73 +322,73 @@ namespace twitter { | |||
| 324 | { | 322 | { |
| 325 | new(&_user_and_list._user) user(other._user_and_list._user); | 323 | new(&_user_and_list._user) user(other._user_and_list._user); |
| 326 | new(&_user_and_list._list) list(other._user_and_list._list); | 324 | new(&_user_and_list._list) list(other._user_and_list._list); |
| 327 | 325 | ||
| 328 | break; | 326 | break; |
| 329 | } | 327 | } |
| 330 | 328 | ||
| 331 | case type::stall: | 329 | case type::stall: |
| 332 | case type::follow_limit: | 330 | case type::follow_limit: |
| 333 | case type::unknown_warning: | 331 | case type::unknown_warning: |
| 334 | { | 332 | { |
| 335 | new(&_warning) std::string(other._warning); | 333 | new(&_warning) std::string(other._warning); |
| 336 | 334 | ||
| 337 | break; | 335 | break; |
| 338 | } | 336 | } |
| 339 | 337 | ||
| 340 | case type::deletion: | 338 | case type::deletion: |
| 341 | case type::scrub_location: | 339 | case type::scrub_location: |
| 342 | { | 340 | { |
| 343 | _user_id_and_tweet_id._user_id = other._user_id_and_tweet_id._user_id; | 341 | _user_id_and_tweet_id._user_id = other._user_id_and_tweet_id._user_id; |
| 344 | _user_id_and_tweet_id._tweet_id = other._user_id_and_tweet_id._tweet_id; | 342 | _user_id_and_tweet_id._tweet_id = other._user_id_and_tweet_id._tweet_id; |
| 345 | 343 | ||
| 346 | break; | 344 | break; |
| 347 | } | 345 | } |
| 348 | 346 | ||
| 349 | case type::limit: | 347 | case type::limit: |
| 350 | { | 348 | { |
| 351 | _limit = other._limit; | 349 | _limit = other._limit; |
| 352 | 350 | ||
| 353 | break; | 351 | break; |
| 354 | } | 352 | } |
| 355 | 353 | ||
| 356 | case type::withhold_status: | 354 | case type::withhold_status: |
| 357 | { | 355 | { |
| 358 | _withhold_status._user_id = other._withhold_status._user_id; | 356 | _withhold_status._user_id = other._withhold_status._user_id; |
| 359 | _withhold_status._tweet_id = other._withhold_status._tweet_id; | 357 | _withhold_status._tweet_id = other._withhold_status._tweet_id; |
| 360 | new(&_withhold_status._countries) std::vector<std::string>(other._withhold_status._countries); | 358 | new(&_withhold_status._countries) std::vector<std::string>(other._withhold_status._countries); |
| 361 | 359 | ||
| 362 | break; | 360 | break; |
| 363 | } | 361 | } |
| 364 | 362 | ||
| 365 | case type::withhold_user: | 363 | case type::withhold_user: |
| 366 | { | 364 | { |
| 367 | _withhold_user._user_id = other._withhold_user._user_id; | 365 | _withhold_user._user_id = other._withhold_user._user_id; |
| 368 | new(&_withhold_user._countries) std::vector<std::string>(other._withhold_user._countries); | 366 | new(&_withhold_user._countries) std::vector<std::string>(other._withhold_user._countries); |
| 369 | 367 | ||
| 370 | break; | 368 | break; |
| 371 | } | 369 | } |
| 372 | 370 | ||
| 373 | case type::disconnect: | 371 | case type::disconnect: |
| 374 | { | 372 | { |
| 375 | _disconnect = other._disconnect; | 373 | _disconnect = other._disconnect; |
| 376 | 374 | ||
| 377 | break; | 375 | break; |
| 378 | } | 376 | } |
| 379 | 377 | ||
| 380 | case type::friends: | 378 | case type::friends: |
| 381 | { | 379 | { |
| 382 | new(&_friends) std::set<user_id>(other._friends); | 380 | new(&_friends) std::set<user_id>(other._friends); |
| 383 | 381 | ||
| 384 | break; | 382 | break; |
| 385 | } | 383 | } |
| 386 | 384 | ||
| 387 | case type::direct: | 385 | case type::direct: |
| 388 | { | 386 | { |
| 389 | new(&_direct_message) direct_message(other._direct_message); | 387 | new(&_direct_message) direct_message(other._direct_message); |
| 390 | 388 | ||
| 391 | break; | 389 | break; |
| 392 | } | 390 | } |
| 393 | 391 | ||
| 394 | case type::unknown: | 392 | case type::unknown: |
| 395 | case type::invalid: | 393 | case type::invalid: |
| 396 | { | 394 | { |
| @@ -398,19 +396,19 @@ namespace twitter { | |||
| 398 | } | 396 | } |
| 399 | } | 397 | } |
| 400 | } | 398 | } |
| 401 | 399 | ||
| 402 | notification::notification(notification&& other) : notification() | 400 | notification::notification(notification&& other) : notification() |
| 403 | { | 401 | { |
| 404 | swap(*this, other); | 402 | swap(*this, other); |
| 405 | } | 403 | } |
| 406 | 404 | ||
| 407 | notification& notification::operator=(notification other) | 405 | notification& notification::operator=(notification other) |
| 408 | { | 406 | { |
| 409 | swap(*this, other); | 407 | swap(*this, other); |
| 410 | 408 | ||
| 411 | return *this; | 409 | return *this; |
| 412 | } | 410 | } |
| 413 | 411 | ||
| 414 | notification::~notification() | 412 | notification::~notification() |
| 415 | { | 413 | { |
| 416 | switch (_type) | 414 | switch (_type) |
| @@ -418,10 +416,10 @@ namespace twitter { | |||
| 418 | case type::tweet: | 416 | case type::tweet: |
| 419 | { | 417 | { |
| 420 | _tweet.~tweet(); | 418 | _tweet.~tweet(); |
| 421 | 419 | ||
| 422 | break; | 420 | break; |
| 423 | } | 421 | } |
| 424 | 422 | ||
| 425 | case type::update_user: | 423 | case type::update_user: |
| 426 | case type::block: | 424 | case type::block: |
| 427 | case type::unblock: | 425 | case type::unblock: |
| @@ -430,10 +428,10 @@ namespace twitter { | |||
| 430 | case type::unfollow: | 428 | case type::unfollow: |
| 431 | { | 429 | { |
| 432 | _user.~user(); | 430 | _user.~user(); |
| 433 | 431 | ||
| 434 | break; | 432 | break; |
| 435 | } | 433 | } |
| 436 | 434 | ||
| 437 | case type::favorite: | 435 | case type::favorite: |
| 438 | case type::favorited: | 436 | case type::favorited: |
| 439 | case type::unfavorite: | 437 | case type::unfavorite: |
| @@ -442,19 +440,19 @@ namespace twitter { | |||
| 442 | { | 440 | { |
| 443 | _user_and_tweet._user.~user(); | 441 | _user_and_tweet._user.~user(); |
| 444 | _user_and_tweet._tweet.~tweet(); | 442 | _user_and_tweet._tweet.~tweet(); |
| 445 | 443 | ||
| 446 | break; | 444 | break; |
| 447 | } | 445 | } |
| 448 | 446 | ||
| 449 | case type::list_created: | 447 | case type::list_created: |
| 450 | case type::list_destroyed: | 448 | case type::list_destroyed: |
| 451 | case type::list_updated: | 449 | case type::list_updated: |
| 452 | { | 450 | { |
| 453 | _list.~list(); | 451 | _list.~list(); |
| 454 | 452 | ||
| 455 | break; | 453 | break; |
| 456 | } | 454 | } |
| 457 | 455 | ||
| 458 | case type::list_add: | 456 | case type::list_add: |
| 459 | case type::list_added: | 457 | case type::list_added: |
| 460 | case type::list_remove: | 458 | case type::list_remove: |
| @@ -466,51 +464,51 @@ namespace twitter { | |||
| 466 | { | 464 | { |
| 467 | _user_and_list._user.~user(); | 465 | _user_and_list._user.~user(); |
| 468 | _user_and_list._list.~list(); | 466 | _user_and_list._list.~list(); |
| 469 | 467 | ||
| 470 | break; | 468 | break; |
| 471 | } | 469 | } |
| 472 | 470 | ||
| 473 | case type::stall: | 471 | case type::stall: |
| 474 | case type::follow_limit: | 472 | case type::follow_limit: |
| 475 | case type::unknown_warning: | 473 | case type::unknown_warning: |
| 476 | { | 474 | { |
| 477 | using string_type = std::string; | 475 | using string_type = std::string; |
| 478 | _warning.~string_type(); | 476 | _warning.~string_type(); |
| 479 | 477 | ||
| 480 | break; | 478 | break; |
| 481 | } | 479 | } |
| 482 | 480 | ||
| 483 | case type::withhold_status: | 481 | case type::withhold_status: |
| 484 | { | 482 | { |
| 485 | using list_type = std::vector<std::string>; | 483 | using list_type = std::vector<std::string>; |
| 486 | _withhold_status._countries.~list_type(); | 484 | _withhold_status._countries.~list_type(); |
| 487 | 485 | ||
| 488 | break; | 486 | break; |
| 489 | } | 487 | } |
| 490 | 488 | ||
| 491 | case type::withhold_user: | 489 | case type::withhold_user: |
| 492 | { | 490 | { |
| 493 | using list_type = std::vector<std::string>; | 491 | using list_type = std::vector<std::string>; |
| 494 | _withhold_user._countries.~list_type(); | 492 | _withhold_user._countries.~list_type(); |
| 495 | 493 | ||
| 496 | break; | 494 | break; |
| 497 | } | 495 | } |
| 498 | 496 | ||
| 499 | case type::friends: | 497 | case type::friends: |
| 500 | { | 498 | { |
| 501 | using list_type = std::set<user_id>; | 499 | using list_type = std::set<user_id>; |
| 502 | _friends.~list_type(); | 500 | _friends.~list_type(); |
| 503 | 501 | ||
| 504 | break; | 502 | break; |
| 505 | } | 503 | } |
| 506 | 504 | ||
| 507 | case type::direct: | 505 | case type::direct: |
| 508 | { | 506 | { |
| 509 | _direct_message.~direct_message(); | 507 | _direct_message.~direct_message(); |
| 510 | 508 | ||
| 511 | break; | 509 | break; |
| 512 | } | 510 | } |
| 513 | 511 | ||
| 514 | case type::deletion: | 512 | case type::deletion: |
| 515 | case type::scrub_location: | 513 | case type::scrub_location: |
| 516 | case type::limit: | 514 | case type::limit: |
| @@ -522,11 +520,11 @@ namespace twitter { | |||
| 522 | } | 520 | } |
| 523 | } | 521 | } |
| 524 | } | 522 | } |
| 525 | 523 | ||
| 526 | void swap(notification& first, notification& second) | 524 | void swap(notification& first, notification& second) |
| 527 | { | 525 | { |
| 528 | using type = notification::type; | 526 | using type = notification::type; |
| 529 | 527 | ||
| 530 | type tempType = first._type; | 528 | type tempType = first._type; |
| 531 | tweet tempTweet; | 529 | tweet tempTweet; |
| 532 | user tempUser; | 530 | user tempUser; |
| @@ -539,16 +537,16 @@ namespace twitter { | |||
| 539 | disconnect_code tempDisconnectCode; | 537 | disconnect_code tempDisconnectCode; |
| 540 | std::set<user_id> tempFriends; | 538 | std::set<user_id> tempFriends; |
| 541 | direct_message tempDirectMessage; | 539 | direct_message tempDirectMessage; |
| 542 | 540 | ||
| 543 | switch (first._type) | 541 | switch (first._type) |
| 544 | { | 542 | { |
| 545 | case type::tweet: | 543 | case type::tweet: |
| 546 | { | 544 | { |
| 547 | tempTweet = std::move(first._tweet); | 545 | tempTweet = std::move(first._tweet); |
| 548 | 546 | ||
| 549 | break; | 547 | break; |
| 550 | } | 548 | } |
| 551 | 549 | ||
| 552 | case type::update_user: | 550 | case type::update_user: |
| 553 | case type::block: | 551 | case type::block: |
| 554 | case type::unblock: | 552 | case type::unblock: |
| @@ -557,10 +555,10 @@ namespace twitter { | |||
| 557 | case type::unfollow: | 555 | case type::unfollow: |
| 558 | { | 556 | { |
| 559 | tempUser = std::move(first._user); | 557 | tempUser = std::move(first._user); |
| 560 | 558 | ||
| 561 | break; | 559 | break; |
| 562 | } | 560 | } |
| 563 | 561 | ||
| 564 | case type::favorite: | 562 | case type::favorite: |
| 565 | case type::favorited: | 563 | case type::favorited: |
| 566 | case type::unfavorite: | 564 | case type::unfavorite: |
| @@ -569,19 +567,19 @@ namespace twitter { | |||
| 569 | { | 567 | { |
| 570 | tempTweet = std::move(first._user_and_tweet._tweet); | 568 | tempTweet = std::move(first._user_and_tweet._tweet); |
| 571 | tempUser = std::move(first._user_and_tweet._user); | 569 | tempUser = std::move(first._user_and_tweet._user); |
| 572 | 570 | ||
| 573 | break; | 571 | break; |
| 574 | } | 572 | } |
| 575 | 573 | ||
| 576 | case type::list_created: | 574 | case type::list_created: |
| 577 | case type::list_destroyed: | 575 | case type::list_destroyed: |
| 578 | case type::list_updated: | 576 | case type::list_updated: |
| 579 | { | 577 | { |
| 580 | tempList = std::move(first._list); | 578 | tempList = std::move(first._list); |
| 581 | 579 | ||
| 582 | break; | 580 | break; |
| 583 | } | 581 | } |
| 584 | 582 | ||
| 585 | case type::list_add: | 583 | case type::list_add: |
| 586 | case type::list_added: | 584 | case type::list_added: |
| 587 | case type::list_remove: | 585 | case type::list_remove: |
| @@ -593,97 +591,97 @@ namespace twitter { | |||
| 593 | { | 591 | { |
| 594 | tempList = std::move(first._user_and_list._list); | 592 | tempList = std::move(first._user_and_list._list); |
| 595 | tempUser = std::move(first._user_and_list._user); | 593 | tempUser = std::move(first._user_and_list._user); |
| 596 | 594 | ||
| 597 | break; | 595 | break; |
| 598 | } | 596 | } |
| 599 | 597 | ||
| 600 | case type::stall: | 598 | case type::stall: |
| 601 | case type::follow_limit: | 599 | case type::follow_limit: |
| 602 | case type::unknown_warning: | 600 | case type::unknown_warning: |
| 603 | { | 601 | { |
| 604 | tempWarning = std::move(first._warning); | 602 | tempWarning = std::move(first._warning); |
| 605 | 603 | ||
| 606 | break; | 604 | break; |
| 607 | } | 605 | } |
| 608 | 606 | ||
| 609 | case type::deletion: | 607 | case type::deletion: |
| 610 | case type::scrub_location: | 608 | case type::scrub_location: |
| 611 | { | 609 | { |
| 612 | tempUserId = first._user_id_and_tweet_id._user_id; | 610 | tempUserId = first._user_id_and_tweet_id._user_id; |
| 613 | tempTweetId = first._user_id_and_tweet_id._tweet_id; | 611 | tempTweetId = first._user_id_and_tweet_id._tweet_id; |
| 614 | 612 | ||
| 615 | break; | 613 | break; |
| 616 | } | 614 | } |
| 617 | 615 | ||
| 618 | case type::limit: | 616 | case type::limit: |
| 619 | { | 617 | { |
| 620 | tempLimit = first._limit; | 618 | tempLimit = first._limit; |
| 621 | 619 | ||
| 622 | break; | 620 | break; |
| 623 | } | 621 | } |
| 624 | 622 | ||
| 625 | case type::withhold_status: | 623 | case type::withhold_status: |
| 626 | { | 624 | { |
| 627 | tempUserId = first._withhold_status._user_id; | 625 | tempUserId = first._withhold_status._user_id; |
| 628 | tempTweetId = first._withhold_status._tweet_id; | 626 | tempTweetId = first._withhold_status._tweet_id; |
| 629 | tempCountries = std::move(first._withhold_status._countries); | 627 | tempCountries = std::move(first._withhold_status._countries); |
| 630 | 628 | ||
| 631 | break; | 629 | break; |
| 632 | } | 630 | } |
| 633 | 631 | ||
| 634 | case type::withhold_user: | 632 | case type::withhold_user: |
| 635 | { | 633 | { |
| 636 | tempUserId = first._withhold_user._user_id; | 634 | tempUserId = first._withhold_user._user_id; |
| 637 | tempCountries = std::move(first._withhold_user._countries); | 635 | tempCountries = std::move(first._withhold_user._countries); |
| 638 | 636 | ||
| 639 | break; | 637 | break; |
| 640 | } | 638 | } |
| 641 | 639 | ||
| 642 | case type::disconnect: | 640 | case type::disconnect: |
| 643 | { | 641 | { |
| 644 | tempDisconnectCode = first._disconnect; | 642 | tempDisconnectCode = first._disconnect; |
| 645 | 643 | ||
| 646 | break; | 644 | break; |
| 647 | } | 645 | } |
| 648 | 646 | ||
| 649 | case type::friends: | 647 | case type::friends: |
| 650 | { | 648 | { |
| 651 | tempFriends = std::move(first._friends); | 649 | tempFriends = std::move(first._friends); |
| 652 | 650 | ||
| 653 | break; | 651 | break; |
| 654 | } | 652 | } |
| 655 | 653 | ||
| 656 | case type::direct: | 654 | case type::direct: |
| 657 | { | 655 | { |
| 658 | tempDirectMessage = std::move(first._direct_message); | 656 | tempDirectMessage = std::move(first._direct_message); |
| 659 | 657 | ||
| 660 | break; | 658 | break; |
| 661 | } | 659 | } |
| 662 | 660 | ||
| 663 | case type::invalid: | 661 | case type::invalid: |
| 664 | case type::unknown: | 662 | case type::unknown: |
| 665 | { | 663 | { |
| 666 | break; | 664 | break; |
| 667 | } | 665 | } |
| 668 | } | 666 | } |
| 669 | 667 | ||
| 670 | first.~notification(); | 668 | first.~notification(); |
| 671 | 669 | ||
| 672 | first._type = second._type; | 670 | first._type = second._type; |
| 673 | 671 | ||
| 674 | // Okay now you need to initialize the first with the data from the second | 672 | // Okay now you need to initialize the first with the data from the second |
| 675 | // And then destruct the second and initialize it with the data stored in temp | 673 | // And then destruct the second and initialize it with the data stored in temp |
| 676 | // This is hell | 674 | // This is hell |
| 677 | 675 | ||
| 678 | switch (second._type) | 676 | switch (second._type) |
| 679 | { | 677 | { |
| 680 | case type::tweet: | 678 | case type::tweet: |
| 681 | { | 679 | { |
| 682 | new(&first._tweet) tweet(std::move(second._tweet)); | 680 | new(&first._tweet) tweet(std::move(second._tweet)); |
| 683 | 681 | ||
| 684 | break; | 682 | break; |
| 685 | } | 683 | } |
| 686 | 684 | ||
| 687 | case type::update_user: | 685 | case type::update_user: |
| 688 | case type::block: | 686 | case type::block: |
| 689 | case type::unblock: | 687 | case type::unblock: |
| @@ -692,10 +690,10 @@ namespace twitter { | |||
| 692 | case type::unfollow: | 690 | case type::unfollow: |
| 693 | { | 691 | { |
| 694 | new(&first._user) user(std::move(second._user)); | 692 | new(&first._user) user(std::move(second._user)); |
| 695 | 693 | ||
| 696 | break; | 694 | break; |
| 697 | } | 695 | } |
| 698 | 696 | ||
| 699 | case type::favorite: | 697 | case type::favorite: |
| 700 | case type::favorited: | 698 | case type::favorited: |
| 701 | case type::unfavorite: | 699 | case type::unfavorite: |
| @@ -704,19 +702,19 @@ namespace twitter { | |||
| 704 | { | 702 | { |
| 705 | new(&first._user_and_tweet._user) user(std::move(second._user_and_tweet._user)); | 703 | new(&first._user_and_tweet._user) user(std::move(second._user_and_tweet._user)); |
| 706 | new(&first._user_and_tweet._tweet) tweet(std::move(second._user_and_tweet._tweet)); | 704 | new(&first._user_and_tweet._tweet) tweet(std::move(second._user_and_tweet._tweet)); |
| 707 | 705 | ||
| 708 | break; | 706 | break; |
| 709 | } | 707 | } |
| 710 | 708 | ||
| 711 | case type::list_created: | 709 | case type::list_created: |
| 712 | case type::list_destroyed: | 710 | case type::list_destroyed: |
| 713 | case type::list_updated: | 711 | case type::list_updated: |
| 714 | { | 712 | { |
| 715 | new(&first._list) list(std::move(second._list)); | 713 | new(&first._list) list(std::move(second._list)); |
| 716 | 714 | ||
| 717 | break; | 715 | break; |
| 718 | } | 716 | } |
| 719 | 717 | ||
| 720 | case type::list_add: | 718 | case type::list_add: |
| 721 | case type::list_added: | 719 | case type::list_added: |
| 722 | case type::list_remove: | 720 | case type::list_remove: |
| @@ -728,94 +726,94 @@ namespace twitter { | |||
| 728 | { | 726 | { |
| 729 | new(&first._user_and_list._user) user(std::move(second._user_and_list._user)); | 727 | new(&first._user_and_list._user) user(std::move(second._user_and_list._user)); |
| 730 | new(&first._user_and_list._list) list(std::move(second._user_and_list._list)); | 728 | new(&first._user_and_list._list) list(std::move(second._user_and_list._list)); |
| 731 | 729 | ||
| 732 | break; | 730 | break; |
| 733 | } | 731 | } |
| 734 | 732 | ||
| 735 | case type::stall: | 733 | case type::stall: |
| 736 | case type::follow_limit: | 734 | case type::follow_limit: |
| 737 | case type::unknown_warning: | 735 | case type::unknown_warning: |
| 738 | { | 736 | { |
| 739 | new(&first._warning) std::string(std::move(second._warning)); | 737 | new(&first._warning) std::string(std::move(second._warning)); |
| 740 | 738 | ||
| 741 | break; | 739 | break; |
| 742 | } | 740 | } |
| 743 | 741 | ||
| 744 | case type::deletion: | 742 | case type::deletion: |
| 745 | case type::scrub_location: | 743 | case type::scrub_location: |
| 746 | { | 744 | { |
| 747 | first._user_id_and_tweet_id._user_id = second._user_id_and_tweet_id._user_id; | 745 | first._user_id_and_tweet_id._user_id = second._user_id_and_tweet_id._user_id; |
| 748 | first._user_id_and_tweet_id._tweet_id = second._user_id_and_tweet_id._tweet_id; | 746 | first._user_id_and_tweet_id._tweet_id = second._user_id_and_tweet_id._tweet_id; |
| 749 | 747 | ||
| 750 | break; | 748 | break; |
| 751 | } | 749 | } |
| 752 | 750 | ||
| 753 | case type::limit: | 751 | case type::limit: |
| 754 | { | 752 | { |
| 755 | first._limit = second._limit; | 753 | first._limit = second._limit; |
| 756 | 754 | ||
| 757 | break; | 755 | break; |
| 758 | } | 756 | } |
| 759 | 757 | ||
| 760 | case type::withhold_status: | 758 | case type::withhold_status: |
| 761 | { | 759 | { |
| 762 | first._withhold_status._user_id = second._withhold_status._user_id; | 760 | first._withhold_status._user_id = second._withhold_status._user_id; |
| 763 | first._withhold_status._tweet_id = second._withhold_status._tweet_id; | 761 | first._withhold_status._tweet_id = second._withhold_status._tweet_id; |
| 764 | new(&first._withhold_status._countries) std::vector<std::string>(std::move(second._withhold_status._countries)); | 762 | new(&first._withhold_status._countries) std::vector<std::string>(std::move(second._withhold_status._countries)); |
| 765 | 763 | ||
| 766 | break; | 764 | break; |
| 767 | } | 765 | } |
| 768 | 766 | ||
| 769 | case type::withhold_user: | 767 | case type::withhold_user: |
| 770 | { | 768 | { |
| 771 | first._withhold_user._user_id = second._withhold_user._user_id; | 769 | first._withhold_user._user_id = second._withhold_user._user_id; |
| 772 | new(&first._withhold_user._countries) std::vector<std::string>(std::move(second._withhold_user._countries)); | 770 | new(&first._withhold_user._countries) std::vector<std::string>(std::move(second._withhold_user._countries)); |
| 773 | 771 | ||
| 774 | break; | 772 | break; |
| 775 | } | 773 | } |
| 776 | 774 | ||
| 777 | case type::disconnect: | 775 | case type::disconnect: |
| 778 | { | 776 | { |
| 779 | first._disconnect = second._disconnect; | 777 | first._disconnect = second._disconnect; |
| 780 | 778 | ||
| 781 | break; | 779 | break; |
| 782 | } | 780 | } |
| 783 | 781 | ||
| 784 | case type::friends: | 782 | case type::friends: |
| 785 | { | 783 | { |
| 786 | new(&first._friends) std::set<user_id>(std::move(second._friends)); | 784 | new(&first._friends) std::set<user_id>(std::move(second._friends)); |
| 787 | 785 | ||
| 788 | break; | 786 | break; |
| 789 | } | 787 | } |
| 790 | 788 | ||
| 791 | case type::direct: | 789 | case type::direct: |
| 792 | { | 790 | { |
| 793 | new(&first._direct_message) direct_message(std::move(second._direct_message)); | 791 | new(&first._direct_message) direct_message(std::move(second._direct_message)); |
| 794 | 792 | ||
| 795 | break; | 793 | break; |
| 796 | } | 794 | } |
| 797 | 795 | ||
| 798 | case type::invalid: | 796 | case type::invalid: |
| 799 | case type::unknown: | 797 | case type::unknown: |
| 800 | { | 798 | { |
| 801 | break; | 799 | break; |
| 802 | } | 800 | } |
| 803 | } | 801 | } |
| 804 | 802 | ||
| 805 | // Now destruct the second and initialize it with data from the first | 803 | // Now destruct the second and initialize it with data from the first |
| 806 | second.~notification(); | 804 | second.~notification(); |
| 807 | 805 | ||
| 808 | second._type = tempType; | 806 | second._type = tempType; |
| 809 | 807 | ||
| 810 | switch (tempType) | 808 | switch (tempType) |
| 811 | { | 809 | { |
| 812 | case type::tweet: | 810 | case type::tweet: |
| 813 | { | 811 | { |
| 814 | new(&second._tweet) tweet(std::move(tempTweet)); | 812 | new(&second._tweet) tweet(std::move(tempTweet)); |
| 815 | 813 | ||
| 816 | break; | 814 | break; |
| 817 | } | 815 | } |
| 818 | 816 | ||
| 819 | case type::update_user: | 817 | case type::update_user: |
| 820 | case type::block: | 818 | case type::block: |
| 821 | case type::unblock: | 819 | case type::unblock: |
| @@ -824,10 +822,10 @@ namespace twitter { | |||
| 824 | case type::unfollow: | 822 | case type::unfollow: |
| 825 | { | 823 | { |
| 826 | new(&second._user) user(std::move(tempUser)); | 824 | new(&second._user) user(std::move(tempUser)); |
| 827 | 825 | ||
| 828 | break; | 826 | break; |
| 829 | } | 827 | } |
| 830 | 828 | ||
| 831 | case type::favorite: | 829 | case type::favorite: |
| 832 | case type::favorited: | 830 | case type::favorited: |
| 833 | case type::unfavorite: | 831 | case type::unfavorite: |
| @@ -836,19 +834,19 @@ namespace twitter { | |||
| 836 | { | 834 | { |
| 837 | new(&second._user_and_tweet._user) user(std::move(tempUser)); | 835 | new(&second._user_and_tweet._user) user(std::move(tempUser)); |
| 838 | new(&second._user_and_tweet._tweet) tweet(std::move(tempTweet)); | 836 | new(&second._user_and_tweet._tweet) tweet(std::move(tempTweet)); |
| 839 | 837 | ||
| 840 | break; | 838 | break; |
| 841 | } | 839 | } |
| 842 | 840 | ||
| 843 | case type::list_created: | 841 | case type::list_created: |
| 844 | case type::list_destroyed: | 842 | case type::list_destroyed: |
| 845 | case type::list_updated: | 843 | case type::list_updated: |
| 846 | { | 844 | { |
| 847 | new(&second._list) list(std::move(tempList)); | 845 | new(&second._list) list(std::move(tempList)); |
| 848 | 846 | ||
| 849 | break; | 847 | break; |
| 850 | } | 848 | } |
| 851 | 849 | ||
| 852 | case type::list_add: | 850 | case type::list_add: |
| 853 | case type::list_added: | 851 | case type::list_added: |
| 854 | case type::list_remove: | 852 | case type::list_remove: |
| @@ -860,73 +858,73 @@ namespace twitter { | |||
| 860 | { | 858 | { |
| 861 | new(&second._user_and_list._user) user(std::move(tempUser)); | 859 | new(&second._user_and_list._user) user(std::move(tempUser)); |
| 862 | new(&second._user_and_list._list) list(std::move(tempList)); | 860 | new(&second._user_and_list._list) list(std::move(tempList)); |
| 863 | 861 | ||
| 864 | break; | 862 | break; |
| 865 | } | 863 | } |
| 866 | 864 | ||
| 867 | case type::stall: | 865 | case type::stall: |
| 868 | case type::follow_limit: | 866 | case type::follow_limit: |
| 869 | case type::unknown_warning: | 867 | case type::unknown_warning: |
| 870 | { | 868 | { |
| 871 | new(&second._warning) std::string(std::move(tempWarning)); | 869 | new(&second._warning) std::string(std::move(tempWarning)); |
| 872 | 870 | ||
| 873 | break; | 871 | break; |
| 874 | } | 872 | } |
| 875 | 873 | ||
| 876 | case type::deletion: | 874 | case type::deletion: |
| 877 | case type::scrub_location: | 875 | case type::scrub_location: |
| 878 | { | 876 | { |
| 879 | second._user_id_and_tweet_id._user_id = tempUserId; | 877 | second._user_id_and_tweet_id._user_id = tempUserId; |
| 880 | second._user_id_and_tweet_id._tweet_id = tempTweetId; | 878 | second._user_id_and_tweet_id._tweet_id = tempTweetId; |
| 881 | 879 | ||
| 882 | break; | 880 | break; |
| 883 | } | 881 | } |
| 884 | 882 | ||
| 885 | case type::limit: | 883 | case type::limit: |
| 886 | { | 884 | { |
| 887 | second._limit = tempLimit; | 885 | second._limit = tempLimit; |
| 888 | 886 | ||
| 889 | break; | 887 | break; |
| 890 | } | 888 | } |
| 891 | 889 | ||
| 892 | case type::withhold_status: | 890 | case type::withhold_status: |
| 893 | { | 891 | { |
| 894 | second._withhold_status._user_id = tempUserId; | 892 | second._withhold_status._user_id = tempUserId; |
| 895 | second._withhold_status._tweet_id = tempTweetId; | 893 | second._withhold_status._tweet_id = tempTweetId; |
| 896 | new(&second._withhold_status._countries) std::vector<std::string>(std::move(tempCountries)); | 894 | new(&second._withhold_status._countries) std::vector<std::string>(std::move(tempCountries)); |
| 897 | 895 | ||
| 898 | break; | 896 | break; |
| 899 | } | 897 | } |
| 900 | 898 | ||
| 901 | case type::withhold_user: | 899 | case type::withhold_user: |
| 902 | { | 900 | { |
| 903 | second._withhold_user._user_id = tempUserId; | 901 | second._withhold_user._user_id = tempUserId; |
| 904 | new(&second._withhold_user._countries) std::vector<std::string>(std::move(tempCountries)); | 902 | new(&second._withhold_user._countries) std::vector<std::string>(std::move(tempCountries)); |
| 905 | 903 | ||
| 906 | break; | 904 | break; |
| 907 | } | 905 | } |
| 908 | 906 | ||
| 909 | case type::disconnect: | 907 | case type::disconnect: |
| 910 | { | 908 | { |
| 911 | second._disconnect = tempDisconnectCode; | 909 | second._disconnect = tempDisconnectCode; |
| 912 | 910 | ||
| 913 | break; | 911 | break; |
| 914 | } | 912 | } |
| 915 | 913 | ||
| 916 | case type::friends: | 914 | case type::friends: |
| 917 | { | 915 | { |
| 918 | new(&second._friends) std::set<user_id>(std::move(tempFriends)); | 916 | new(&second._friends) std::set<user_id>(std::move(tempFriends)); |
| 919 | 917 | ||
| 920 | break; | 918 | break; |
| 921 | } | 919 | } |
| 922 | 920 | ||
| 923 | case type::direct: | 921 | case type::direct: |
| 924 | { | 922 | { |
| 925 | new(&second._direct_message) direct_message(std::move(tempDirectMessage)); | 923 | new(&second._direct_message) direct_message(std::move(tempDirectMessage)); |
| 926 | 924 | ||
| 927 | break; | 925 | break; |
| 928 | } | 926 | } |
| 929 | 927 | ||
| 930 | case type::invalid: | 928 | case type::invalid: |
| 931 | case type::unknown: | 929 | case type::unknown: |
| 932 | { | 930 | { |
| @@ -934,7 +932,7 @@ namespace twitter { | |||
| 934 | } | 932 | } |
| 935 | } | 933 | } |
| 936 | } | 934 | } |
| 937 | 935 | ||
| 938 | const tweet& notification::getTweet() const | 936 | const tweet& notification::getTweet() const |
| 939 | { | 937 | { |
| 940 | switch (_type) | 938 | switch (_type) |
| @@ -943,7 +941,7 @@ namespace twitter { | |||
| 943 | { | 941 | { |
| 944 | return _tweet; | 942 | return _tweet; |
| 945 | } | 943 | } |
| 946 | 944 | ||
| 947 | case type::favorite: | 945 | case type::favorite: |
| 948 | case type::favorited: | 946 | case type::favorited: |
| 949 | case type::unfavorite: | 947 | case type::unfavorite: |
| @@ -952,14 +950,14 @@ namespace twitter { | |||
| 952 | { | 950 | { |
| 953 | return _user_and_tweet._tweet; | 951 | return _user_and_tweet._tweet; |
| 954 | } | 952 | } |
| 955 | 953 | ||
| 956 | default: | 954 | default: |
| 957 | { | 955 | { |
| 958 | assert(false); | 956 | assert(false); |
| 959 | } | 957 | } |
| 960 | } | 958 | } |
| 961 | } | 959 | } |
| 962 | 960 | ||
| 963 | const user& notification::getUser() const | 961 | const user& notification::getUser() const |
| 964 | { | 962 | { |
| 965 | switch (_type) | 963 | switch (_type) |
| @@ -973,7 +971,7 @@ namespace twitter { | |||
| 973 | { | 971 | { |
| 974 | return _user; | 972 | return _user; |
| 975 | } | 973 | } |
| 976 | 974 | ||
| 977 | case type::favorite: | 975 | case type::favorite: |
| 978 | case type::favorited: | 976 | case type::favorited: |
| 979 | case type::unfavorite: | 977 | case type::unfavorite: |
| @@ -982,7 +980,7 @@ namespace twitter { | |||
| 982 | { | 980 | { |
| 983 | return _user_and_tweet._user; | 981 | return _user_and_tweet._user; |
| 984 | } | 982 | } |
| 985 | 983 | ||
| 986 | case type::list_add: | 984 | case type::list_add: |
| 987 | case type::list_added: | 985 | case type::list_added: |
| 988 | case type::list_remove: | 986 | case type::list_remove: |
| @@ -994,25 +992,25 @@ namespace twitter { | |||
| 994 | { | 992 | { |
| 995 | return _user_and_list._user; | 993 | return _user_and_list._user; |
| 996 | } | 994 | } |
| 997 | 995 | ||
| 998 | default: | 996 | default: |
| 999 | { | 997 | { |
| 1000 | assert(false); | 998 | assert(false); |
| 1001 | } | 999 | } |
| 1002 | } | 1000 | } |
| 1003 | } | 1001 | } |
| 1004 | 1002 | ||
| 1005 | const list& notification::getList() const | 1003 | const list& notification::getList() const |
| 1006 | { | 1004 | { |
| 1007 | switch (_type) | 1005 | switch (_type) |
| 1008 | { | 1006 | { |
| 1009 | case type::list_created: | 1007 | case type::list_created: |
| 1010 | case type::list_destroyed: | 1008 | case type::list_destroyed: |
| 1011 | case type::list_updated: | 1009 | case type::list_updated: |
| 1012 | { | 1010 | { |
| 1013 | return _list; | 1011 | return _list; |
| 1014 | } | 1012 | } |
| 1015 | 1013 | ||
| 1016 | case type::list_add: | 1014 | case type::list_add: |
| 1017 | case type::list_added: | 1015 | case type::list_added: |
| 1018 | case type::list_remove: | 1016 | case type::list_remove: |
| @@ -1024,14 +1022,14 @@ namespace twitter { | |||
| 1024 | { | 1022 | { |
| 1025 | return _user_and_list._list; | 1023 | return _user_and_list._list; |
| 1026 | } | 1024 | } |
| 1027 | 1025 | ||
| 1028 | default: | 1026 | default: |
| 1029 | { | 1027 | { |
| 1030 | assert(false); | 1028 | assert(false); |
| 1031 | } | 1029 | } |
| 1032 | } | 1030 | } |
| 1033 | } | 1031 | } |
| 1034 | 1032 | ||
| 1035 | tweet_id notification::getTweetID() const | 1033 | tweet_id notification::getTweetID() const |
| 1036 | { | 1034 | { |
| 1037 | switch (_type) | 1035 | switch (_type) |
| @@ -1041,19 +1039,19 @@ namespace twitter { | |||
| 1041 | { | 1039 | { |
| 1042 | return _user_id_and_tweet_id._tweet_id; | 1040 | return _user_id_and_tweet_id._tweet_id; |
| 1043 | } | 1041 | } |
| 1044 | 1042 | ||
| 1045 | case type::withhold_status: | 1043 | case type::withhold_status: |
| 1046 | { | 1044 | { |
| 1047 | return _withhold_status._tweet_id; | 1045 | return _withhold_status._tweet_id; |
| 1048 | } | 1046 | } |
| 1049 | 1047 | ||
| 1050 | default: | 1048 | default: |
| 1051 | { | 1049 | { |
| 1052 | assert(false); | 1050 | assert(false); |
| 1053 | } | 1051 | } |
| 1054 | } | 1052 | } |
| 1055 | } | 1053 | } |
| 1056 | 1054 | ||
| 1057 | void notification::setTweetID(tweet_id _arg) | 1055 | void notification::setTweetID(tweet_id _arg) |
| 1058 | { | 1056 | { |
| 1059 | switch (_type) | 1057 | switch (_type) |
| @@ -1063,34 +1061,34 @@ namespace twitter { | |||
| 1063 | { | 1061 | { |
| 1064 | _user_id_and_tweet_id._tweet_id = _arg;; | 1062 | _user_id_and_tweet_id._tweet_id = _arg;; |
| 1065 | } | 1063 | } |
| 1066 | 1064 | ||
| 1067 | case type::withhold_status: | 1065 | case type::withhold_status: |
| 1068 | { | 1066 | { |
| 1069 | _withhold_status._tweet_id = _arg; | 1067 | _withhold_status._tweet_id = _arg; |
| 1070 | } | 1068 | } |
| 1071 | 1069 | ||
| 1072 | default: | 1070 | default: |
| 1073 | { | 1071 | { |
| 1074 | assert(false); | 1072 | assert(false); |
| 1075 | } | 1073 | } |
| 1076 | } | 1074 | } |
| 1077 | } | 1075 | } |
| 1078 | 1076 | ||
| 1079 | user_id notification::getUserID() const | 1077 | user_id notification::getUserID() const |
| 1080 | { | 1078 | { |
| 1081 | switch (_type) | 1079 | switch (_type) |
| 1082 | { | 1080 | { |
| 1083 | case type::deletion: | 1081 | case type::deletion: |
| 1084 | case type::scrub_location: | 1082 | case type::scrub_location: |
| 1085 | { | 1083 | { |
| 1086 | return _user_id_and_tweet_id._user_id; | 1084 | return _user_id_and_tweet_id._user_id; |
| 1087 | } | 1085 | } |
| 1088 | 1086 | ||
| 1089 | case type::withhold_status: | 1087 | case type::withhold_status: |
| 1090 | { | 1088 | { |
| 1091 | return _withhold_status._user_id; | 1089 | return _withhold_status._user_id; |
| 1092 | } | 1090 | } |
| 1093 | 1091 | ||
| 1094 | case type::withhold_user: | 1092 | case type::withhold_user: |
| 1095 | { | 1093 | { |
| 1096 | return _withhold_user._user_id; | 1094 | return _withhold_user._user_id; |
| @@ -1102,22 +1100,22 @@ namespace twitter { | |||
| 1102 | } | 1100 | } |
| 1103 | } | 1101 | } |
| 1104 | } | 1102 | } |
| 1105 | 1103 | ||
| 1106 | void notification::setUserID(user_id _arg) | 1104 | void notification::setUserID(user_id _arg) |
| 1107 | { | 1105 | { |
| 1108 | switch (_type) | 1106 | switch (_type) |
| 1109 | { | 1107 | { |
| 1110 | case type::deletion: | 1108 | case type::deletion: |
| 1111 | case type::scrub_location: | 1109 | case type::scrub_location: |
| 1112 | { | 1110 | { |
| 1113 | _user_id_and_tweet_id._user_id = _arg; | 1111 | _user_id_and_tweet_id._user_id = _arg; |
| 1114 | } | 1112 | } |
| 1115 | 1113 | ||
| 1116 | case type::withhold_status: | 1114 | case type::withhold_status: |
| 1117 | { | 1115 | { |
| 1118 | _withhold_status._user_id = _arg; | 1116 | _withhold_status._user_id = _arg; |
| 1119 | } | 1117 | } |
| 1120 | 1118 | ||
| 1121 | case type::withhold_user: | 1119 | case type::withhold_user: |
| 1122 | { | 1120 | { |
| 1123 | _withhold_user._user_id = _arg; | 1121 | _withhold_user._user_id = _arg; |
| @@ -1129,16 +1127,16 @@ namespace twitter { | |||
| 1129 | } | 1127 | } |
| 1130 | } | 1128 | } |
| 1131 | } | 1129 | } |
| 1132 | 1130 | ||
| 1133 | const std::vector<std::string>& notification::getCountries() const | 1131 | const std::vector<std::string>& notification::getCountries() const |
| 1134 | { | 1132 | { |
| 1135 | switch (_type) | 1133 | switch (_type) |
| 1136 | { | 1134 | { |
| 1137 | case type::withhold_status: | 1135 | case type::withhold_status: |
| 1138 | { | 1136 | { |
| 1139 | return _withhold_status._countries; | 1137 | return _withhold_status._countries; |
| 1140 | } | 1138 | } |
| 1141 | 1139 | ||
| 1142 | case type::withhold_user: | 1140 | case type::withhold_user: |
| 1143 | { | 1141 | { |
| 1144 | return _withhold_user._countries; | 1142 | return _withhold_user._countries; |
| @@ -1150,49 +1148,49 @@ namespace twitter { | |||
| 1150 | } | 1148 | } |
| 1151 | } | 1149 | } |
| 1152 | } | 1150 | } |
| 1153 | 1151 | ||
| 1154 | disconnect_code notification::getDisconnectCode() const | 1152 | disconnect_code notification::getDisconnectCode() const |
| 1155 | { | 1153 | { |
| 1156 | assert(_type == type::disconnect); | 1154 | assert(_type == type::disconnect); |
| 1157 | 1155 | ||
| 1158 | return _disconnect; | 1156 | return _disconnect; |
| 1159 | } | 1157 | } |
| 1160 | 1158 | ||
| 1161 | void notification::setDisconnectCode(disconnect_code _arg) | 1159 | void notification::setDisconnectCode(disconnect_code _arg) |
| 1162 | { | 1160 | { |
| 1163 | assert(_type == type::disconnect); | 1161 | assert(_type == type::disconnect); |
| 1164 | 1162 | ||
| 1165 | _disconnect = _arg; | 1163 | _disconnect = _arg; |
| 1166 | } | 1164 | } |
| 1167 | 1165 | ||
| 1168 | const std::set<user_id>& notification::getFriends() const | 1166 | const std::set<user_id>& notification::getFriends() const |
| 1169 | { | 1167 | { |
| 1170 | assert(_type == type::friends); | 1168 | assert(_type == type::friends); |
| 1171 | 1169 | ||
| 1172 | return _friends; | 1170 | return _friends; |
| 1173 | } | 1171 | } |
| 1174 | 1172 | ||
| 1175 | const direct_message& notification::getDirectMessage() const | 1173 | const direct_message& notification::getDirectMessage() const |
| 1176 | { | 1174 | { |
| 1177 | assert(_type == type::direct); | 1175 | assert(_type == type::direct); |
| 1178 | 1176 | ||
| 1179 | return _direct_message; | 1177 | return _direct_message; |
| 1180 | } | 1178 | } |
| 1181 | 1179 | ||
| 1182 | int notification::getLimit() const | 1180 | int notification::getLimit() const |
| 1183 | { | 1181 | { |
| 1184 | assert(_type == type::limit); | 1182 | assert(_type == type::limit); |
| 1185 | 1183 | ||
| 1186 | return _limit; | 1184 | return _limit; |
| 1187 | } | 1185 | } |
| 1188 | 1186 | ||
| 1189 | void notification::setLimit(int _arg) | 1187 | void notification::setLimit(int _arg) |
| 1190 | { | 1188 | { |
| 1191 | assert(_type == type::limit); | 1189 | assert(_type == type::limit); |
| 1192 | 1190 | ||
| 1193 | _limit = _arg; | 1191 | _limit = _arg; |
| 1194 | } | 1192 | } |
| 1195 | 1193 | ||
| 1196 | const std::string& notification::getWarning() const | 1194 | const std::string& notification::getWarning() const |
| 1197 | { | 1195 | { |
| 1198 | switch (_type) | 1196 | switch (_type) |
| @@ -1203,12 +1201,12 @@ namespace twitter { | |||
| 1203 | { | 1201 | { |
| 1204 | return _warning; | 1202 | return _warning; |
| 1205 | } | 1203 | } |
| 1206 | 1204 | ||
| 1207 | default: | 1205 | default: |
| 1208 | { | 1206 | { |
| 1209 | assert(false); | 1207 | assert(false); |
| 1210 | } | 1208 | } |
| 1211 | } | 1209 | } |
| 1212 | } | 1210 | } |
| 1213 | 1211 | ||
| 1214 | }; | 1212 | }; |
| diff --git a/src/notification.h b/src/notification.h index a6dd6f4..ad649c3 100644 --- a/src/notification.h +++ b/src/notification.h | |||
| @@ -10,9 +10,9 @@ | |||
| 10 | #include "direct_message.h" | 10 | #include "direct_message.h" |
| 11 | 11 | ||
| 12 | namespace twitter { | 12 | namespace twitter { |
| 13 | 13 | ||
| 14 | class client; | 14 | class client; |
| 15 | 15 | ||
| 16 | enum class disconnect_code | 16 | enum class disconnect_code |
| 17 | { | 17 | { |
| 18 | shutdown, | 18 | shutdown, |
| @@ -27,13 +27,13 @@ namespace twitter { | |||
| 27 | load, | 27 | load, |
| 28 | unknown | 28 | unknown |
| 29 | }; | 29 | }; |
| 30 | 30 | ||
| 31 | class notification { | 31 | class notification { |
| 32 | public: | 32 | public: |
| 33 | enum class type { | 33 | enum class type { |
| 34 | // Tweet object | 34 | // Tweet object |
| 35 | tweet, | 35 | tweet, |
| 36 | 36 | ||
| 37 | // User object | 37 | // User object |
| 38 | update_user, | 38 | update_user, |
| 39 | block, | 39 | block, |
| @@ -41,19 +41,19 @@ namespace twitter { | |||
| 41 | follow, | 41 | follow, |
| 42 | followed, | 42 | followed, |
| 43 | unfollow, | 43 | unfollow, |
| 44 | 44 | ||
| 45 | // User and tweet | 45 | // User and tweet |
| 46 | favorite, | 46 | favorite, |
| 47 | favorited, | 47 | favorited, |
| 48 | unfavorite, | 48 | unfavorite, |
| 49 | unfavorited, | 49 | unfavorited, |
| 50 | quoted, | 50 | quoted, |
| 51 | 51 | ||
| 52 | // List | 52 | // List |
| 53 | list_created, | 53 | list_created, |
| 54 | list_destroyed, | 54 | list_destroyed, |
| 55 | list_updated, | 55 | list_updated, |
| 56 | 56 | ||
| 57 | // User and list | 57 | // User and list |
| 58 | list_add, | 58 | list_add, |
| 59 | list_added, | 59 | list_added, |
| @@ -63,16 +63,16 @@ namespace twitter { | |||
| 63 | list_subscribed, | 63 | list_subscribed, |
| 64 | list_unsubscribe, | 64 | list_unsubscribe, |
| 65 | list_unsubscribed, | 65 | list_unsubscribed, |
| 66 | 66 | ||
| 67 | // Warning | 67 | // Warning |
| 68 | stall, | 68 | stall, |
| 69 | follow_limit, | 69 | follow_limit, |
| 70 | unknown_warning, | 70 | unknown_warning, |
| 71 | 71 | ||
| 72 | // User ID and tweet ID | 72 | // User ID and tweet ID |
| 73 | deletion, | 73 | deletion, |
| 74 | scrub_location, | 74 | scrub_location, |
| 75 | 75 | ||
| 76 | // Special | 76 | // Special |
| 77 | limit, | 77 | limit, |
| 78 | withhold_status, | 78 | withhold_status, |
| @@ -80,78 +80,78 @@ namespace twitter { | |||
| 80 | disconnect, | 80 | disconnect, |
| 81 | friends, | 81 | friends, |
| 82 | direct, | 82 | direct, |
| 83 | 83 | ||
| 84 | // Nothing | 84 | // Nothing |
| 85 | unknown, | 85 | unknown, |
| 86 | invalid | 86 | invalid |
| 87 | }; | 87 | }; |
| 88 | 88 | ||
| 89 | type getType() const; | 89 | type getType() const; |
| 90 | 90 | ||
| 91 | notification() {} | 91 | notification() {} |
| 92 | notification(const client& tclient, std::string data); | 92 | notification(const user& currentUser, std::string data); |
| 93 | 93 | ||
| 94 | notification(const notification& other); | 94 | notification(const notification& other); |
| 95 | notification(notification&& other); | 95 | notification(notification&& other); |
| 96 | notification& operator=(notification other); | 96 | notification& operator=(notification other); |
| 97 | ~notification(); | 97 | ~notification(); |
| 98 | 98 | ||
| 99 | friend void swap(notification& first, notification& second); | 99 | friend void swap(notification& first, notification& second); |
| 100 | 100 | ||
| 101 | const tweet& getTweet() const; | 101 | const tweet& getTweet() const; |
| 102 | tweet& getTweet() | 102 | tweet& getTweet() |
| 103 | { | 103 | { |
| 104 | return const_cast<tweet&>(static_cast<const notification&>(*this).getTweet()); | 104 | return const_cast<tweet&>(static_cast<const notification&>(*this).getTweet()); |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | const user& getUser() const; | 107 | const user& getUser() const; |
| 108 | user& getUser() | 108 | user& getUser() |
| 109 | { | 109 | { |
| 110 | return const_cast<user&>(static_cast<const notification&>(*this).getUser()); | 110 | return const_cast<user&>(static_cast<const notification&>(*this).getUser()); |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | const list& getList() const; | 113 | const list& getList() const; |
| 114 | list& getList() | 114 | list& getList() |
| 115 | { | 115 | { |
| 116 | return const_cast<list&>(static_cast<const notification&>(*this).getList()); | 116 | return const_cast<list&>(static_cast<const notification&>(*this).getList()); |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | tweet_id getTweetID() const; | 119 | tweet_id getTweetID() const; |
| 120 | void setTweetID(tweet_id _arg); | 120 | void setTweetID(tweet_id _arg); |
| 121 | 121 | ||
| 122 | user_id getUserID() const; | 122 | user_id getUserID() const; |
| 123 | void setUserID(user_id _arg); | 123 | void setUserID(user_id _arg); |
| 124 | 124 | ||
| 125 | const std::vector<std::string>& getCountries() const; | 125 | const std::vector<std::string>& getCountries() const; |
| 126 | std::vector<std::string>& getCountries() | 126 | std::vector<std::string>& getCountries() |
| 127 | { | 127 | { |
| 128 | return const_cast<std::vector<std::string>&>(static_cast<const notification&>(*this).getCountries()); | 128 | return const_cast<std::vector<std::string>&>(static_cast<const notification&>(*this).getCountries()); |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | disconnect_code getDisconnectCode() const; | 131 | disconnect_code getDisconnectCode() const; |
| 132 | void setDisconnectCode(disconnect_code _arg); | 132 | void setDisconnectCode(disconnect_code _arg); |
| 133 | 133 | ||
| 134 | const std::set<user_id>& getFriends() const; | 134 | const std::set<user_id>& getFriends() const; |
| 135 | std::set<user_id>& getFriends() | 135 | std::set<user_id>& getFriends() |
| 136 | { | 136 | { |
| 137 | return const_cast<std::set<user_id>&>(static_cast<const notification&>(*this).getFriends()); | 137 | return const_cast<std::set<user_id>&>(static_cast<const notification&>(*this).getFriends()); |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | const direct_message& getDirectMessage() const; | 140 | const direct_message& getDirectMessage() const; |
| 141 | direct_message& getDirectMessage() | 141 | direct_message& getDirectMessage() |
| 142 | { | 142 | { |
| 143 | return const_cast<direct_message&>(static_cast<const notification&>(*this).getDirectMessage()); | 143 | return const_cast<direct_message&>(static_cast<const notification&>(*this).getDirectMessage()); |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | int getLimit() const; | 146 | int getLimit() const; |
| 147 | void setLimit(int _arg); | 147 | void setLimit(int _arg); |
| 148 | 148 | ||
| 149 | const std::string& getWarning() const; | 149 | const std::string& getWarning() const; |
| 150 | std::string& getWarning() | 150 | std::string& getWarning() |
| 151 | { | 151 | { |
| 152 | return const_cast<std::string&>(static_cast<const notification&>(*this).getWarning()); | 152 | return const_cast<std::string&>(static_cast<const notification&>(*this).getWarning()); |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | private: | 155 | private: |
| 156 | union { | 156 | union { |
| 157 | tweet _tweet; | 157 | tweet _tweet; |
| @@ -186,7 +186,7 @@ namespace twitter { | |||
| 186 | }; | 186 | }; |
| 187 | type _type = type::invalid; | 187 | type _type = type::invalid; |
| 188 | }; | 188 | }; |
| 189 | 189 | ||
| 190 | }; | 190 | }; |
| 191 | 191 | ||
| 192 | #endif /* end of include guard: NOTIFICATION_H_69AEF4CC */ | 192 | #endif /* end of include guard: NOTIFICATION_H_69AEF4CC */ |
| diff --git a/src/request.cpp b/src/request.cpp new file mode 100644 index 0000000..a79c7f0 --- /dev/null +++ b/src/request.cpp | |||
| @@ -0,0 +1,264 @@ | |||
| 1 | #include "request.h" | ||
| 2 | #include <json.hpp> | ||
| 3 | #include "codes.h" | ||
| 4 | |||
| 5 | // These are here for debugging curl stuff | ||
| 6 | |||
| 7 | static | ||
| 8 | void dump(const char *text, | ||
| 9 | FILE *stream, unsigned char *ptr, size_t size) | ||
| 10 | { | ||
| 11 | size_t i; | ||
| 12 | size_t c; | ||
| 13 | unsigned int width=80; | ||
| 14 | |||
| 15 | fprintf(stream, "%s, %10.10ld bytes (0x%8.8lx)\n", | ||
| 16 | text, (long)size, (long)size); | ||
| 17 | |||
| 18 | for(i=0; i<size; i+= width) { | ||
| 19 | fprintf(stream, "%4.4lx: ", (long)i); | ||
| 20 | |||
| 21 | /* show hex to the left | ||
| 22 | for(c = 0; c < width; c++) { | ||
| 23 | if(i+c < size) | ||
| 24 | fprintf(stream, "%02x ", ptr[i+c]); | ||
| 25 | else | ||
| 26 | fputs(" ", stream); | ||
| 27 | }*/ | ||
| 28 | |||
| 29 | /* show data on the right */ | ||
| 30 | for(c = 0; (c < width) && (i+c < size); c++) { | ||
| 31 | char x = (ptr[i+c] >= 0x20 && ptr[i+c] < 0x80) ? ptr[i+c] : '.'; | ||
| 32 | fputc(x, stream); | ||
| 33 | } | ||
| 34 | |||
| 35 | fputc('\n', stream); /* newline */ | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | static | ||
| 40 | int my_trace(CURL *handle, curl_infotype type, | ||
| 41 | char *data, size_t size, | ||
| 42 | void *userp) | ||
| 43 | { | ||
| 44 | const char *text; | ||
| 45 | (void)handle; /* prevent compiler warning */ | ||
| 46 | |||
| 47 | switch (type) { | ||
| 48 | case CURLINFO_TEXT: | ||
| 49 | fprintf(stderr, "== Info: %s", data); | ||
| 50 | default: /* in case a new one is introduced to shock us */ | ||
| 51 | return 0; | ||
| 52 | |||
| 53 | case CURLINFO_HEADER_OUT: | ||
| 54 | text = "=> Send header"; | ||
| 55 | break; | ||
| 56 | case CURLINFO_DATA_OUT: | ||
| 57 | text = "=> Send data"; | ||
| 58 | break; | ||
| 59 | case CURLINFO_SSL_DATA_OUT: | ||
| 60 | text = "=> Send SSL data"; | ||
| 61 | break; | ||
| 62 | case CURLINFO_HEADER_IN: | ||
| 63 | text = "<= Recv header"; | ||
| 64 | break; | ||
| 65 | case CURLINFO_DATA_IN: | ||
| 66 | text = "<= Recv data"; | ||
| 67 | break; | ||
| 68 | case CURLINFO_SSL_DATA_IN: | ||
| 69 | text = "<= Recv SSL data"; | ||
| 70 | break; | ||
| 71 | } | ||
| 72 | |||
| 73 | dump(text, stderr, (unsigned char *)data, size); | ||
| 74 | return 0; | ||
| 75 | } | ||
| 76 | |||
| 77 | namespace twitter { | ||
| 78 | |||
| 79 | request::request( | ||
| 80 | std::string url) try : | ||
| 81 | ios_(output_), | ||
| 82 | conn_(ios_) | ||
| 83 | { | ||
| 84 | conn_.add<CURLOPT_URL>(url.c_str()); | ||
| 85 | } catch (const curl::curl_easy_exception& error) | ||
| 86 | { | ||
| 87 | std::throw_with_nested(connection_error()); | ||
| 88 | } | ||
| 89 | |||
| 90 | std::string request::perform() | ||
| 91 | { | ||
| 92 | try | ||
| 93 | { | ||
| 94 | conn_.perform(); | ||
| 95 | } catch (const curl::curl_easy_exception& error) | ||
| 96 | { | ||
| 97 | std::throw_with_nested(connection_error()); | ||
| 98 | } | ||
| 99 | |||
| 100 | int response_code = conn_.get_info<CURLINFO_RESPONSE_CODE>().get(); | ||
| 101 | std::string result = output_.str(); | ||
| 102 | |||
| 103 | if (response_code / 100 != 2) | ||
| 104 | { | ||
| 105 | nlohmann::json response_json; | ||
| 106 | |||
| 107 | try | ||
| 108 | { | ||
| 109 | response_json = nlohmann::json::parse(result); | ||
| 110 | } catch (const std::invalid_argument& e) | ||
| 111 | { | ||
| 112 | std::throw_with_nested(invalid_response(result)); | ||
| 113 | } | ||
| 114 | |||
| 115 | for (nlohmann::json& error : response_json["errors"]) | ||
| 116 | { | ||
| 117 | int error_code; | ||
| 118 | std::string error_message; | ||
| 119 | |||
| 120 | try | ||
| 121 | { | ||
| 122 | error_code = error["code"].get<int>(); | ||
| 123 | error_message = error["message"].get<std::string>(); | ||
| 124 | } catch (const std::domain_error& e) | ||
| 125 | { | ||
| 126 | std::throw_with_nested(invalid_response(result)); | ||
| 127 | } | ||
| 128 | |||
| 129 | switch (error_code) | ||
| 130 | { | ||
| 131 | case 32: | ||
| 132 | case 135: | ||
| 133 | case 215: | ||
| 134 | throw bad_auth(error_message); | ||
| 135 | |||
| 136 | case 44: | ||
| 137 | throw invalid_media(error_message); | ||
| 138 | |||
| 139 | case 64: | ||
| 140 | throw account_suspended(error_message); | ||
| 141 | |||
| 142 | case 88: | ||
| 143 | throw rate_limit_exceeded(error_message); | ||
| 144 | |||
| 145 | case 89: | ||
| 146 | throw bad_token(error_message); | ||
| 147 | |||
| 148 | case 130: | ||
| 149 | throw server_overloaded(error_message); | ||
| 150 | |||
| 151 | case 131: | ||
| 152 | throw server_error(error_message); | ||
| 153 | |||
| 154 | case 185: | ||
| 155 | throw update_limit_exceeded(error_message); | ||
| 156 | |||
| 157 | case 186: | ||
| 158 | throw bad_length(error_message); | ||
| 159 | |||
| 160 | case 187: | ||
| 161 | throw duplicate_status(error_message); | ||
| 162 | |||
| 163 | case 226: | ||
| 164 | throw suspected_spam(error_message); | ||
| 165 | |||
| 166 | case 261: | ||
| 167 | throw write_restricted(error_message); | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | if (response_code == 429) | ||
| 172 | { | ||
| 173 | throw rate_limit_exceeded("HTTP 429 Too Many Requests"); | ||
| 174 | } else if (response_code == 500) | ||
| 175 | { | ||
| 176 | throw server_error("HTTP 500 Internal Server Error"); | ||
| 177 | } else if (response_code == 502) | ||
| 178 | { | ||
| 179 | throw server_unavailable("HTTP 502 Bad Gateway"); | ||
| 180 | } else if (response_code == 503) | ||
| 181 | { | ||
| 182 | throw server_overloaded("HTTP 503 Service Unavailable"); | ||
| 183 | } else if (response_code == 504) | ||
| 184 | { | ||
| 185 | throw server_timeout("HTTP 504 Gateway Timeout"); | ||
| 186 | } | ||
| 187 | |||
| 188 | throw unknown_error(response_code, result); | ||
| 189 | } | ||
| 190 | |||
| 191 | return result; | ||
| 192 | } | ||
| 193 | |||
| 194 | get::get( | ||
| 195 | const auth& tauth, | ||
| 196 | std::string url) try : | ||
| 197 | request(url) | ||
| 198 | { | ||
| 199 | std::string oauthHeader = | ||
| 200 | tauth.getClient().getFormattedHttpHeader(OAuth::Http::Get, url, ""); | ||
| 201 | |||
| 202 | if (!oauthHeader.empty()) | ||
| 203 | { | ||
| 204 | headers_.add(std::move(oauthHeader)); | ||
| 205 | } | ||
| 206 | |||
| 207 | conn_.add<CURLOPT_HTTPHEADER>(headers_.get()); | ||
| 208 | } catch (const OAuth::ParseError& error) | ||
| 209 | { | ||
| 210 | std::throw_with_nested(connection_error()); | ||
| 211 | } catch (const curl::curl_easy_exception& error) | ||
| 212 | { | ||
| 213 | std::throw_with_nested(connection_error()); | ||
| 214 | } | ||
| 215 | |||
| 216 | post::post( | ||
| 217 | const auth& tauth, | ||
| 218 | std::string url, | ||
| 219 | std::string datastr) try : | ||
| 220 | request(url) | ||
| 221 | { | ||
| 222 | std::string oauthHeader = | ||
| 223 | tauth.getClient().getFormattedHttpHeader(OAuth::Http::Post, url, datastr); | ||
| 224 | |||
| 225 | if (!oauthHeader.empty()) | ||
| 226 | { | ||
| 227 | headers_.add(std::move(oauthHeader)); | ||
| 228 | } | ||
| 229 | |||
| 230 | conn_.add<CURLOPT_HTTPHEADER>(headers_.get()); | ||
| 231 | conn_.add<CURLOPT_COPYPOSTFIELDS>(datastr.c_str()); | ||
| 232 | } catch (const OAuth::ParseError& error) | ||
| 233 | { | ||
| 234 | std::throw_with_nested(connection_error()); | ||
| 235 | } catch (const curl::curl_easy_exception& error) | ||
| 236 | { | ||
| 237 | std::throw_with_nested(connection_error()); | ||
| 238 | } | ||
| 239 | |||
| 240 | multipost::multipost( | ||
| 241 | const auth& tauth, | ||
| 242 | std::string url, | ||
| 243 | const curl_httppost* fields) try : | ||
| 244 | request(url) | ||
| 245 | { | ||
| 246 | std::string oauthHeader = | ||
| 247 | tauth.getClient().getFormattedHttpHeader(OAuth::Http::Post, url, ""); | ||
| 248 | |||
| 249 | if (!oauthHeader.empty()) | ||
| 250 | { | ||
| 251 | headers_.add(std::move(oauthHeader)); | ||
| 252 | } | ||
| 253 | |||
| 254 | conn_.add<CURLOPT_HTTPHEADER>(headers_.get()); | ||
| 255 | conn_.add<CURLOPT_HTTPPOST>(fields); | ||
| 256 | } catch (const OAuth::ParseError& error) | ||
| 257 | { | ||
| 258 | std::throw_with_nested(connection_error()); | ||
| 259 | } catch (const curl::curl_easy_exception& error) | ||
| 260 | { | ||
| 261 | std::throw_with_nested(connection_error()); | ||
| 262 | } | ||
| 263 | |||
| 264 | } | ||
| diff --git a/src/request.h b/src/request.h new file mode 100644 index 0000000..1672d71 --- /dev/null +++ b/src/request.h | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | #ifndef REQUEST_H_9D3C30E2 | ||
| 2 | #define REQUEST_H_9D3C30E2 | ||
| 3 | |||
| 4 | #include <string> | ||
| 5 | #include <sstream> | ||
| 6 | #include <curl_easy.h> | ||
| 7 | #include <curl_header.h> | ||
| 8 | #include "auth.h" | ||
| 9 | |||
| 10 | namespace twitter { | ||
| 11 | |||
| 12 | class request | ||
| 13 | { | ||
| 14 | public: | ||
| 15 | |||
| 16 | explicit request(std::string url); | ||
| 17 | |||
| 18 | std::string perform(); | ||
| 19 | |||
| 20 | private: | ||
| 21 | |||
| 22 | std::ostringstream output_; | ||
| 23 | curl::curl_ios<std::ostringstream> ios_; | ||
| 24 | |||
| 25 | protected: | ||
| 26 | |||
| 27 | curl::curl_easy conn_; | ||
| 28 | }; | ||
| 29 | |||
| 30 | class get : public request | ||
| 31 | { | ||
| 32 | public: | ||
| 33 | |||
| 34 | get( | ||
| 35 | const auth& tauth, | ||
| 36 | std::string url); | ||
| 37 | |||
| 38 | private: | ||
| 39 | |||
| 40 | curl::curl_header headers_; | ||
| 41 | }; | ||
| 42 | |||
| 43 | class post : public request | ||
| 44 | { | ||
| 45 | public: | ||
| 46 | |||
| 47 | post( | ||
| 48 | const auth& tauth, | ||
| 49 | std::string url, | ||
| 50 | std::string datastr); | ||
| 51 | |||
| 52 | private: | ||
| 53 | |||
| 54 | curl::curl_header headers_; | ||
| 55 | }; | ||
| 56 | |||
| 57 | class multipost : public request | ||
| 58 | { | ||
| 59 | public: | ||
| 60 | |||
| 61 | multipost( | ||
| 62 | const auth& tauth, | ||
| 63 | std::string url, | ||
| 64 | const curl_httppost* fields); | ||
| 65 | |||
| 66 | private: | ||
| 67 | |||
| 68 | curl::curl_header headers_; | ||
| 69 | }; | ||
| 70 | |||
| 71 | } | ||
| 72 | |||
| 73 | #endif /* end of include guard: REQUEST_H_9D3C30E2 */ | ||
| diff --git a/src/stream.cpp b/src/stream.cpp index cb55ee8..86d177c 100644 --- a/src/stream.cpp +++ b/src/stream.cpp | |||
| @@ -4,23 +4,27 @@ | |||
| 4 | #include <curl_header.h> | 4 | #include <curl_header.h> |
| 5 | #include "util.h" | 5 | #include "util.h" |
| 6 | #include "notification.h" | 6 | #include "notification.h" |
| 7 | #include "client.h" | 7 | #include "request.h" |
| 8 | 8 | ||
| 9 | namespace twitter { | 9 | namespace twitter { |
| 10 | 10 | ||
| 11 | stream::stream( | 11 | stream::stream( |
| 12 | const client& tclient, | 12 | const auth& tauth, |
| 13 | notify_callback callback, | 13 | notify_callback callback, |
| 14 | bool with_followings, | 14 | bool with_followings, |
| 15 | bool receive_all_replies, | 15 | bool receive_all_replies, |
| 16 | std::list<std::string> track, | 16 | std::list<std::string> track, |
| 17 | std::list<bounding_box> locations) : | 17 | std::list<bounding_box> locations) : |
| 18 | _client(tclient), | 18 | _auth(tauth), |
| 19 | _notify(callback), | 19 | _notify(callback), |
| 20 | _currentUser(get( | ||
| 21 | _auth, | ||
| 22 | "https://api.twitter.com/1.1/account/verify_credentials.json") | ||
| 23 | .perform()), | ||
| 20 | _thread(&stream::run, this, generateUrl(with_followings, receive_all_replies, track, locations)) | 24 | _thread(&stream::run, this, generateUrl(with_followings, receive_all_replies, track, locations)) |
| 21 | { | 25 | { |
| 22 | } | 26 | } |
| 23 | 27 | ||
| 24 | stream::~stream() | 28 | stream::~stream() |
| 25 | { | 29 | { |
| 26 | if (_thread.joinable()) | 30 | if (_thread.joinable()) |
| @@ -29,7 +33,7 @@ namespace twitter { | |||
| 29 | _thread.join(); | 33 | _thread.join(); |
| 30 | } | 34 | } |
| 31 | } | 35 | } |
| 32 | 36 | ||
| 33 | std::string stream::generateUrl( | 37 | std::string stream::generateUrl( |
| 34 | bool with_followings, | 38 | bool with_followings, |
| 35 | bool receive_all_replies, | 39 | bool receive_all_replies, |
| @@ -37,68 +41,68 @@ namespace twitter { | |||
| 37 | std::list<bounding_box> locations) | 41 | std::list<bounding_box> locations) |
| 38 | { | 42 | { |
| 39 | std::list<std::string> arguments; | 43 | std::list<std::string> arguments; |
| 40 | 44 | ||
| 41 | if (receive_all_replies) | 45 | if (receive_all_replies) |
| 42 | { | 46 | { |
| 43 | arguments.push_back("replies=all"); | 47 | arguments.push_back("replies=all"); |
| 44 | } | 48 | } |
| 45 | 49 | ||
| 46 | if (!with_followings) | 50 | if (!with_followings) |
| 47 | { | 51 | { |
| 48 | arguments.push_back("with=user"); | 52 | arguments.push_back("with=user"); |
| 49 | } | 53 | } |
| 50 | 54 | ||
| 51 | if (!track.empty()) | 55 | if (!track.empty()) |
| 52 | { | 56 | { |
| 53 | std::ostringstream trackstr; | 57 | std::ostringstream trackstr; |
| 54 | trackstr << "track="; | 58 | trackstr << "track="; |
| 55 | 59 | ||
| 56 | for (auto it = std::begin(track); it != std::end(track); it++) | 60 | for (auto it = std::begin(track); it != std::end(track); it++) |
| 57 | { | 61 | { |
| 58 | if (it != std::begin(track)) | 62 | if (it != std::begin(track)) |
| 59 | { | 63 | { |
| 60 | trackstr << ","; | 64 | trackstr << ","; |
| 61 | } | 65 | } |
| 62 | 66 | ||
| 63 | trackstr << OAuth::HttpEncodeQueryValue(*it); | 67 | trackstr << OAuth::HttpEncodeQueryValue(*it); |
| 64 | } | 68 | } |
| 65 | 69 | ||
| 66 | arguments.push_back(trackstr.str()); | 70 | arguments.push_back(trackstr.str()); |
| 67 | } | 71 | } |
| 68 | 72 | ||
| 69 | if (!locations.empty()) | 73 | if (!locations.empty()) |
| 70 | { | 74 | { |
| 71 | std::ostringstream localstr; | 75 | std::ostringstream localstr; |
| 72 | localstr << "locations="; | 76 | localstr << "locations="; |
| 73 | 77 | ||
| 74 | for (auto it = std::begin(locations); it != std::end(locations); it++) | 78 | for (auto it = std::begin(locations); it != std::end(locations); it++) |
| 75 | { | 79 | { |
| 76 | if (it != std::begin(locations)) | 80 | if (it != std::begin(locations)) |
| 77 | { | 81 | { |
| 78 | localstr << ","; | 82 | localstr << ","; |
| 79 | } | 83 | } |
| 80 | 84 | ||
| 81 | localstr << (double)it->getSouthWestLongitude() << ","; | 85 | localstr << (double)it->getSouthWestLongitude() << ","; |
| 82 | localstr << (double)it->getSouthWestLatitude() << ","; | 86 | localstr << (double)it->getSouthWestLatitude() << ","; |
| 83 | localstr << (double)it->getNorthEastLongitude() << ","; | 87 | localstr << (double)it->getNorthEastLongitude() << ","; |
| 84 | localstr << (double)it->getNorthEastLatitude(); | 88 | localstr << (double)it->getNorthEastLatitude(); |
| 85 | } | 89 | } |
| 86 | 90 | ||
| 87 | arguments.push_back(localstr.str()); | 91 | arguments.push_back(localstr.str()); |
| 88 | } | 92 | } |
| 89 | 93 | ||
| 90 | std::ostringstream urlstr; | 94 | std::ostringstream urlstr; |
| 91 | urlstr << "https://userstream.twitter.com/1.1/user.json"; | 95 | urlstr << "https://userstream.twitter.com/1.1/user.json"; |
| 92 | 96 | ||
| 93 | if (!arguments.empty()) | 97 | if (!arguments.empty()) |
| 94 | { | 98 | { |
| 95 | urlstr << "?"; | 99 | urlstr << "?"; |
| 96 | urlstr << implode(std::begin(arguments), std::end(arguments), "&"); | 100 | urlstr << implode(std::begin(arguments), std::end(arguments), "&"); |
| 97 | } | 101 | } |
| 98 | 102 | ||
| 99 | return urlstr.str(); | 103 | return urlstr.str(); |
| 100 | } | 104 | } |
| 101 | 105 | ||
| 102 | void stream::run(std::string url) | 106 | void stream::run(std::string url) |
| 103 | { | 107 | { |
| 104 | _backoff_type = backoff::none; | 108 | _backoff_type = backoff::none; |
| @@ -108,15 +112,15 @@ namespace twitter { | |||
| 108 | curl::curl_ios<stream> ios(this, [] (void* contents, size_t size, size_t nmemb, void* userp) { | 112 | curl::curl_ios<stream> ios(this, [] (void* contents, size_t size, size_t nmemb, void* userp) { |
| 109 | return static_cast<stream*>(userp)->write(static_cast<char*>(contents), size, nmemb); | 113 | return static_cast<stream*>(userp)->write(static_cast<char*>(contents), size, nmemb); |
| 110 | }); | 114 | }); |
| 111 | 115 | ||
| 112 | curl::curl_easy conn(ios); | 116 | curl::curl_easy conn(ios); |
| 113 | curl::curl_header headers; | 117 | curl::curl_header headers; |
| 114 | std::string oauth_header; | 118 | std::string oauth_header; |
| 115 | 119 | ||
| 116 | try | 120 | try |
| 117 | { | 121 | { |
| 118 | oauth_header = _client._oauth_client->getFormattedHttpHeader(OAuth::Http::Get, url, ""); | 122 | oauth_header = _auth.getClient().getFormattedHttpHeader(OAuth::Http::Get, url, ""); |
| 119 | 123 | ||
| 120 | if (!oauth_header.empty()) | 124 | if (!oauth_header.empty()) |
| 121 | { | 125 | { |
| 122 | headers.add(oauth_header); | 126 | headers.add(oauth_header); |
| @@ -126,10 +130,10 @@ namespace twitter { | |||
| 126 | std::cout << "Error generating OAuth header:" << std::endl; | 130 | std::cout << "Error generating OAuth header:" << std::endl; |
| 127 | std::cout << error.what() << std::endl; | 131 | std::cout << error.what() << std::endl; |
| 128 | std::cout << "This is likely due to a malformed URL." << std::endl; | 132 | std::cout << "This is likely due to a malformed URL." << std::endl; |
| 129 | 133 | ||
| 130 | assert(false); | 134 | assert(false); |
| 131 | } | 135 | } |
| 132 | 136 | ||
| 133 | try | 137 | try |
| 134 | { | 138 | { |
| 135 | conn.add<CURLOPT_HEADERFUNCTION>(nullptr); | 139 | conn.add<CURLOPT_HEADERFUNCTION>(nullptr); |
| @@ -146,10 +150,10 @@ namespace twitter { | |||
| 146 | } catch (const curl::curl_exception& error) | 150 | } catch (const curl::curl_exception& error) |
| 147 | { | 151 | { |
| 148 | error.print_traceback(); | 152 | error.print_traceback(); |
| 149 | 153 | ||
| 150 | assert(false); | 154 | assert(false); |
| 151 | } | 155 | } |
| 152 | 156 | ||
| 153 | bool failure = false; | 157 | bool failure = false; |
| 154 | try | 158 | try |
| 155 | { | 159 | { |
| @@ -169,7 +173,7 @@ namespace twitter { | |||
| 169 | } | 173 | } |
| 170 | } | 174 | } |
| 171 | } | 175 | } |
| 172 | 176 | ||
| 173 | if (!failure) | 177 | if (!failure) |
| 174 | { | 178 | { |
| 175 | long response_code = conn.get_info<CURLINFO_RESPONSE_CODE>().get(); | 179 | long response_code = conn.get_info<CURLINFO_RESPONSE_CODE>().get(); |
| @@ -198,7 +202,7 @@ namespace twitter { | |||
| 198 | } | 202 | } |
| 199 | } | 203 | } |
| 200 | } | 204 | } |
| 201 | 205 | ||
| 202 | std::this_thread::sleep_for(_backoff_amount); | 206 | std::this_thread::sleep_for(_backoff_amount); |
| 203 | 207 | ||
| 204 | switch (_backoff_type) | 208 | switch (_backoff_type) |
| @@ -209,35 +213,35 @@ namespace twitter { | |||
| 209 | { | 213 | { |
| 210 | _backoff_amount += std::chrono::milliseconds(250); | 214 | _backoff_amount += std::chrono::milliseconds(250); |
| 211 | } | 215 | } |
| 212 | 216 | ||
| 213 | break; | 217 | break; |
| 214 | } | 218 | } |
| 215 | 219 | ||
| 216 | case backoff::http: | 220 | case backoff::http: |
| 217 | { | 221 | { |
| 218 | if (_backoff_amount < std::chrono::seconds(320)) | 222 | if (_backoff_amount < std::chrono::seconds(320)) |
| 219 | { | 223 | { |
| 220 | _backoff_amount *= 2; | 224 | _backoff_amount *= 2; |
| 221 | } | 225 | } |
| 222 | 226 | ||
| 223 | break; | 227 | break; |
| 224 | } | 228 | } |
| 225 | 229 | ||
| 226 | case backoff::rate_limit: | 230 | case backoff::rate_limit: |
| 227 | { | 231 | { |
| 228 | _backoff_amount *= 2; | 232 | _backoff_amount *= 2; |
| 229 | 233 | ||
| 230 | break; | 234 | break; |
| 231 | } | 235 | } |
| 232 | 236 | ||
| 233 | case backoff::none: | 237 | case backoff::none: |
| 234 | { | 238 | { |
| 235 | break; | 239 | break; |
| 236 | } | 240 | } |
| 237 | } | 241 | } |
| 238 | } | 242 | } |
| 239 | } | 243 | } |
| 240 | 244 | ||
| 241 | size_t stream::write(char* ptr, size_t size, size_t nmemb) | 245 | size_t stream::write(char* ptr, size_t size, size_t nmemb) |
| 242 | { | 246 | { |
| 243 | for (size_t i = 0; i < size*nmemb; i++) | 247 | for (size_t i = 0; i < size*nmemb; i++) |
| @@ -245,38 +249,38 @@ namespace twitter { | |||
| 245 | if (ptr[i] == '\r') | 249 | if (ptr[i] == '\r') |
| 246 | { | 250 | { |
| 247 | i++; // Skip the \n | 251 | i++; // Skip the \n |
| 248 | 252 | ||
| 249 | if (!_buffer.empty()) | 253 | if (!_buffer.empty()) |
| 250 | { | 254 | { |
| 251 | notification n(_client, _buffer); | 255 | notification n(_currentUser, _buffer); |
| 252 | if (n.getType() == notification::type::friends) | 256 | if (n.getType() == notification::type::friends) |
| 253 | { | 257 | { |
| 254 | _established = true; | 258 | _established = true; |
| 255 | _backoff_type = backoff::none; | 259 | _backoff_type = backoff::none; |
| 256 | _backoff_amount = std::chrono::milliseconds(0); | 260 | _backoff_amount = std::chrono::milliseconds(0); |
| 257 | } | 261 | } |
| 258 | 262 | ||
| 259 | _notify(std::move(n)); | 263 | _notify(std::move(n)); |
| 260 | 264 | ||
| 261 | _buffer = ""; | 265 | _buffer = ""; |
| 262 | } | 266 | } |
| 263 | } else { | 267 | } else { |
| 264 | _buffer.push_back(ptr[i]); | 268 | _buffer.push_back(ptr[i]); |
| 265 | } | 269 | } |
| 266 | } | 270 | } |
| 267 | 271 | ||
| 268 | time(&_last_write); | 272 | time(&_last_write); |
| 269 | 273 | ||
| 270 | return size*nmemb; | 274 | return size*nmemb; |
| 271 | } | 275 | } |
| 272 | 276 | ||
| 273 | int stream::progress() | 277 | int stream::progress() |
| 274 | { | 278 | { |
| 275 | if (_stop) | 279 | if (_stop) |
| 276 | { | 280 | { |
| 277 | return 1; | 281 | return 1; |
| 278 | } | 282 | } |
| 279 | 283 | ||
| 280 | if (_established) | 284 | if (_established) |
| 281 | { | 285 | { |
| 282 | if (difftime(time(NULL), _last_write) >= 90) | 286 | if (difftime(time(NULL), _last_write) >= 90) |
| @@ -284,8 +288,8 @@ namespace twitter { | |||
| 284 | return 1; | 288 | return 1; |
| 285 | } | 289 | } |
| 286 | } | 290 | } |
| 287 | 291 | ||
| 288 | return 0; | 292 | return 0; |
| 289 | } | 293 | } |
| 290 | 294 | ||
| 291 | } | 295 | } |
| diff --git a/src/stream.h b/src/stream.h index b682ce2..f6ce91e 100644 --- a/src/stream.h +++ b/src/stream.h | |||
| @@ -7,32 +7,35 @@ | |||
| 7 | #include <chrono> | 7 | #include <chrono> |
| 8 | #include <thread> | 8 | #include <thread> |
| 9 | #include "bounding_box.h" | 9 | #include "bounding_box.h" |
| 10 | #include "auth.h" | ||
| 11 | #include "user.h" | ||
| 10 | 12 | ||
| 11 | namespace twitter { | 13 | namespace twitter { |
| 12 | 14 | ||
| 13 | class client; | ||
| 14 | class notification; | 15 | class notification; |
| 15 | 16 | ||
| 16 | class stream { | 17 | class |
| 18 | [[deprecated("The Twitter streaming API will sunset on August 16th, 2018")]] | ||
| 19 | stream { | ||
| 17 | public: | 20 | public: |
| 18 | 21 | ||
| 19 | typedef std::function<void(notification _notification)> notify_callback; | 22 | typedef std::function<void(notification _notification)> notify_callback; |
| 20 | 23 | ||
| 21 | stream( | 24 | stream( |
| 22 | const client& tclient, | 25 | const auth& tauth, |
| 23 | notify_callback callback, | 26 | notify_callback callback, |
| 24 | bool with_followings = true, | 27 | bool with_followings = true, |
| 25 | bool receive_all_replies = false, | 28 | bool receive_all_replies = false, |
| 26 | std::list<std::string> track = {}, | 29 | std::list<std::string> track = {}, |
| 27 | std::list<bounding_box> locations = {}); | 30 | std::list<bounding_box> locations = {}); |
| 28 | 31 | ||
| 29 | ~stream(); | 32 | ~stream(); |
| 30 | 33 | ||
| 31 | stream(const stream& other) = delete; | 34 | stream(const stream& other) = delete; |
| 32 | stream(stream&& other) = delete; | 35 | stream(stream&& other) = delete; |
| 33 | stream& operator=(const stream& other) = delete; | 36 | stream& operator=(const stream& other) = delete; |
| 34 | stream& operator=(stream&& other) = delete; | 37 | stream& operator=(stream&& other) = delete; |
| 35 | 38 | ||
| 36 | private: | 39 | private: |
| 37 | enum class backoff { | 40 | enum class backoff { |
| 38 | none, | 41 | none, |
| @@ -40,18 +43,18 @@ namespace twitter { | |||
| 40 | http, | 43 | http, |
| 41 | rate_limit | 44 | rate_limit |
| 42 | }; | 45 | }; |
| 43 | 46 | ||
| 44 | static std::string generateUrl( | 47 | static std::string generateUrl( |
| 45 | bool with_followings, | 48 | bool with_followings, |
| 46 | bool receive_all_replies, | 49 | bool receive_all_replies, |
| 47 | std::list<std::string> track, | 50 | std::list<std::string> track, |
| 48 | std::list<bounding_box> locations); | 51 | std::list<bounding_box> locations); |
| 49 | 52 | ||
| 50 | void run(std::string url); | 53 | void run(std::string url); |
| 51 | int progress(); | 54 | int progress(); |
| 52 | size_t write(char* ptr, size_t size, size_t nmemb); | 55 | size_t write(char* ptr, size_t size, size_t nmemb); |
| 53 | 56 | ||
| 54 | const client& _client; | 57 | const auth& _auth; |
| 55 | notify_callback _notify; | 58 | notify_callback _notify; |
| 56 | bool _stop = false; | 59 | bool _stop = false; |
| 57 | std::string _buffer; | 60 | std::string _buffer; |
| @@ -59,9 +62,10 @@ namespace twitter { | |||
| 59 | bool _established = false; | 62 | bool _established = false; |
| 60 | backoff _backoff_type = backoff::none; | 63 | backoff _backoff_type = backoff::none; |
| 61 | std::chrono::milliseconds _backoff_amount; | 64 | std::chrono::milliseconds _backoff_amount; |
| 65 | user _currentUser; | ||
| 62 | std::thread _thread; | 66 | std::thread _thread; |
| 63 | }; | 67 | }; |
| 64 | 68 | ||
| 65 | } | 69 | } |
| 66 | 70 | ||
| 67 | #endif /* end of include guard: STREAM_H_E9146952 */ | 71 | #endif /* end of include guard: STREAM_H_E9146952 */ |
| diff --git a/src/timeline.cpp b/src/timeline.cpp new file mode 100644 index 0000000..fd75a69 --- /dev/null +++ b/src/timeline.cpp | |||
| @@ -0,0 +1,82 @@ | |||
| 1 | #include "timeline.h" | ||
| 2 | #include <sstream> | ||
| 3 | #include <json.hpp> | ||
| 4 | #include "codes.h" | ||
| 5 | #include "util.h" | ||
| 6 | #include "request.h" | ||
| 7 | |||
| 8 | namespace twitter { | ||
| 9 | |||
| 10 | timeline::timeline( | ||
| 11 | const auth& tauth, | ||
| 12 | std::string url) : | ||
| 13 | auth_(tauth), | ||
| 14 | url_(std::move(url)) | ||
| 15 | { | ||
| 16 | } | ||
| 17 | |||
| 18 | std::list<tweet> timeline::poll() | ||
| 19 | { | ||
| 20 | tweet_id maxId; | ||
| 21 | std::list<tweet> result; | ||
| 22 | |||
| 23 | for (int i = 0; i < 5; i++) | ||
| 24 | { | ||
| 25 | std::ostringstream urlstr; | ||
| 26 | urlstr << url_; | ||
| 27 | |||
| 28 | std::list<std::string> arguments; | ||
| 29 | |||
| 30 | if (i > 0) | ||
| 31 | { | ||
| 32 | arguments.push_back("max_id=" + std::to_string(maxId)); | ||
| 33 | } | ||
| 34 | |||
| 35 | if (hasSince_) | ||
| 36 | { | ||
| 37 | arguments.push_back("since_id=" + std::to_string(sinceId_)); | ||
| 38 | } | ||
| 39 | |||
| 40 | if (!arguments.empty()) | ||
| 41 | { | ||
| 42 | urlstr << "?"; | ||
| 43 | urlstr << implode(std::begin(arguments), std::end(arguments), "&"); | ||
| 44 | } | ||
| 45 | |||
| 46 | std::string theUrl = urlstr.str(); | ||
| 47 | std::string response = get(auth_, theUrl).perform(); | ||
| 48 | |||
| 49 | try | ||
| 50 | { | ||
| 51 | nlohmann::json rjs = nlohmann::json::parse(response); | ||
| 52 | |||
| 53 | if (rjs.empty()) | ||
| 54 | { | ||
| 55 | break; | ||
| 56 | } | ||
| 57 | |||
| 58 | for (auto& single : rjs) | ||
| 59 | { | ||
| 60 | result.emplace_back(single.dump()); | ||
| 61 | } | ||
| 62 | } catch (const std::invalid_argument& error) | ||
| 63 | { | ||
| 64 | std::throw_with_nested(invalid_response(response)); | ||
| 65 | } catch (const std::domain_error& error) | ||
| 66 | { | ||
| 67 | std::throw_with_nested(invalid_response(response)); | ||
| 68 | } | ||
| 69 | |||
| 70 | maxId = result.back().getID() - 1; | ||
| 71 | } | ||
| 72 | |||
| 73 | if (!result.empty()) | ||
| 74 | { | ||
| 75 | sinceId_ = result.front().getID(); | ||
| 76 | hasSince_ = true; | ||
| 77 | } | ||
| 78 | |||
| 79 | return result; | ||
| 80 | } | ||
| 81 | |||
| 82 | }; | ||
| diff --git a/src/timeline.h b/src/timeline.h new file mode 100644 index 0000000..60ce78d --- /dev/null +++ b/src/timeline.h | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | #ifndef TIMELINE_H_D359681C | ||
| 2 | #define TIMELINE_H_D359681C | ||
| 3 | |||
| 4 | #include <functional> | ||
| 5 | #include <list> | ||
| 6 | #include <string> | ||
| 7 | #include "auth.h" | ||
| 8 | #include "tweet.h" | ||
| 9 | |||
| 10 | namespace twitter { | ||
| 11 | |||
| 12 | class timeline { | ||
| 13 | public: | ||
| 14 | |||
| 15 | timeline( | ||
| 16 | const auth& tauth, | ||
| 17 | std::string url); | ||
| 18 | |||
| 19 | std::list<tweet> poll(); | ||
| 20 | |||
| 21 | private: | ||
| 22 | |||
| 23 | const auth& auth_; | ||
| 24 | std::string url_; | ||
| 25 | bool hasSince_ = false; | ||
| 26 | tweet_id sinceId_; | ||
| 27 | }; | ||
| 28 | |||
| 29 | } | ||
| 30 | |||
| 31 | #endif /* end of include guard: TIMELINE_H_D359681C */ | ||
| diff --git a/src/tweet.cpp b/src/tweet.cpp index 864bcd8..1c869f9 100644 --- a/src/tweet.cpp +++ b/src/tweet.cpp | |||
| @@ -12,13 +12,13 @@ namespace twitter { | |||
| 12 | auto json = nlohmann::json::parse(data); | 12 | auto json = nlohmann::json::parse(data); |
| 13 | _id = json["id"].get<tweet_id>(); | 13 | _id = json["id"].get<tweet_id>(); |
| 14 | _text = json["text"].get<std::string>(); | 14 | _text = json["text"].get<std::string>(); |
| 15 | _author = make_unique<user>(json["user"].dump()); | 15 | _author = std::make_unique<user>(json["user"].dump()); |
| 16 | 16 | ||
| 17 | if (!json["retweeted_status"].is_null()) | 17 | if (!json["retweeted_status"].is_null()) |
| 18 | { | 18 | { |
| 19 | _is_retweet = true; | 19 | _is_retweet = true; |
| 20 | 20 | ||
| 21 | _retweeted_status = make_unique<tweet>(json["retweeted_status"].dump()); | 21 | _retweeted_status = std::make_unique<tweet>(json["retweeted_status"].dump()); |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | if (!json["entities"].is_null()) | 24 | if (!json["entities"].is_null()) |
| @@ -45,12 +45,12 @@ namespace twitter { | |||
| 45 | _valid = other._valid; | 45 | _valid = other._valid; |
| 46 | _id = other._id; | 46 | _id = other._id; |
| 47 | _text = other._text; | 47 | _text = other._text; |
| 48 | _author = make_unique<user>(*other._author); | 48 | _author = std::make_unique<user>(*other._author); |
| 49 | _is_retweet = other._is_retweet; | 49 | _is_retweet = other._is_retweet; |
| 50 | 50 | ||
| 51 | if (_is_retweet) | 51 | if (_is_retweet) |
| 52 | { | 52 | { |
| 53 | _retweeted_status = make_unique<tweet>(*other._retweeted_status); | 53 | _retweeted_status = std::make_unique<tweet>(*other._retweeted_status); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | _mentions = other._mentions; | 56 | _mentions = other._mentions; |
| diff --git a/src/twitter.h b/src/twitter.h index 1ba4394..a4f336e 100644 --- a/src/twitter.h +++ b/src/twitter.h | |||
| @@ -11,6 +11,7 @@ namespace twitter { | |||
| 11 | #include "util.h" | 11 | #include "util.h" |
| 12 | #include "auth.h" | 12 | #include "auth.h" |
| 13 | #include "client.h" | 13 | #include "client.h" |
| 14 | #include "timeline.h" | ||
| 14 | #include "stream.h" | 15 | #include "stream.h" |
| 15 | #include "tweet.h" | 16 | #include "tweet.h" |
| 16 | #include "user.h" | 17 | #include "user.h" |
| diff --git a/src/util.h b/src/util.h index 9084e81..8cbe054 100644 --- a/src/util.h +++ b/src/util.h | |||
| @@ -6,31 +6,25 @@ | |||
| 6 | #include <memory> | 6 | #include <memory> |
| 7 | 7 | ||
| 8 | namespace twitter { | 8 | namespace twitter { |
| 9 | 9 | ||
| 10 | template <class InputIterator> | 10 | template <class InputIterator> |
| 11 | std::string implode(InputIterator first, InputIterator last, std::string delimiter) | 11 | std::string implode(InputIterator first, InputIterator last, std::string delimiter) |
| 12 | { | 12 | { |
| 13 | std::stringstream result; | 13 | std::stringstream result; |
| 14 | 14 | ||
| 15 | for (InputIterator it = first; it != last; it++) | 15 | for (InputIterator it = first; it != last; it++) |
| 16 | { | 16 | { |
| 17 | if (it != first) | 17 | if (it != first) |
| 18 | { | 18 | { |
| 19 | result << delimiter; | 19 | result << delimiter; |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | result << *it; | 22 | result << *it; |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | return result.str(); | 25 | return result.str(); |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | template<typename T, typename... Args> | ||
| 29 | std::unique_ptr<T> make_unique(Args&&... args) | ||
| 30 | { | ||
| 31 | return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); | ||
| 32 | } | ||
| 33 | |||
| 34 | }; | 28 | }; |
| 35 | 29 | ||
| 36 | #endif /* end of include guard: UTIL_H_440DEAA0 */ | 30 | #endif /* end of include guard: UTIL_H_440DEAA0 */ |
