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 | 368 | ||||
-rw-r--r-- | src/client.h | 36 | ||||
-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, 859 insertions, 759 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 6fea80a..b7eb9d1 100644 --- a/src/client.cpp +++ b/src/client.cpp | |||
@@ -2,342 +2,22 @@ | |||
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 | 10 | ||
85 | class request | 11 | client::client( |
86 | { | 12 | const auth& _arg) : |
87 | public: | 13 | auth_(_arg), |
88 | 14 | currentUser_( | |
89 | explicit request(std::string url) try | 15 | get(auth_, |
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 | |||
181 | if (response_code == 429) | ||
182 | { | ||
183 | throw rate_limit_exceeded("HTTP 429 Too Many Requests"); | ||
184 | } else if (response_code == 500) | ||
185 | { | ||
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; |
@@ -350,7 +30,7 @@ namespace twitter { | |||
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()); |
@@ -370,7 +50,7 @@ namespace twitter { | |||
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()); |
@@ -404,7 +84,7 @@ namespace twitter { | |||
404 | } | 84 | } |
405 | 85 | ||
406 | std::string init_response = | 86 | std::string init_response = |
407 | multipost(*_oauth_client, | 87 | multipost(auth_, |
408 | "https://upload.twitter.com/1.1/media/upload.json", | 88 | "https://upload.twitter.com/1.1/media/upload.json", |
409 | form.get()) | 89 | form.get()) |
410 | .perform(); | 90 | .perform(); |
@@ -435,7 +115,7 @@ namespace twitter { | |||
435 | assert(false); | 115 | assert(false); |
436 | } | 116 | } |
437 | 117 | ||
438 | multipost(*_oauth_client, "https://upload.twitter.com/1.1/media/upload.json", append_form_post).perform(); | 118 | multipost(auth_, "https://upload.twitter.com/1.1/media/upload.json", append_form_post).perform(); |
439 | 119 | ||
440 | curl_formfree(append_form_post); | 120 | curl_formfree(append_form_post); |
441 | 121 | ||
@@ -450,7 +130,7 @@ namespace twitter { | |||
450 | finalize_form.add(media_id_name, media_id_cont); | 130 | finalize_form.add(media_id_name, media_id_cont); |
451 | 131 | ||
452 | std::string finalize_response = | 132 | std::string finalize_response = |
453 | multipost(*_oauth_client, | 133 | multipost(auth_, |
454 | "https://upload.twitter.com/1.1/media/upload.json", | 134 | "https://upload.twitter.com/1.1/media/upload.json", |
455 | finalize_form.get()) | 135 | finalize_form.get()) |
456 | .perform(); | 136 | .perform(); |
@@ -472,7 +152,7 @@ namespace twitter { | |||
472 | 152 | ||
473 | for (;;) | 153 | for (;;) |
474 | { | 154 | { |
475 | std::string status_response = get(*_oauth_client, datastr.str()).perform(); | 155 | std::string status_response = get(auth_, datastr.str()).perform(); |
476 | 156 | ||
477 | try | 157 | try |
478 | { | 158 | { |
@@ -499,9 +179,7 @@ namespace twitter { | |||
499 | return media_id; | 179 | return media_id; |
500 | } catch (const curl::curl_exception& error) | 180 | } catch (const curl::curl_exception& error) |
501 | { | 181 | { |
502 | error.print_traceback(); | 182 | std::throw_with_nested(connection_error()); |
503 | |||
504 | assert(false); | ||
505 | } | 183 | } |
506 | 184 | ||
507 | std::set<user_id> client::getFriends(user_id id) const | 185 | std::set<user_id> client::getFriends(user_id id) const |
@@ -518,7 +196,7 @@ namespace twitter { | |||
518 | urlstream << cursor; | 196 | urlstream << cursor; |
519 | 197 | ||
520 | std::string url = urlstream.str(); | 198 | std::string url = urlstream.str(); |
521 | std::string response_data = get(*_oauth_client, url).perform(); | 199 | std::string response_data = get(auth_, url).perform(); |
522 | 200 | ||
523 | try | 201 | try |
524 | { | 202 | { |
@@ -562,7 +240,7 @@ namespace twitter { | |||
562 | urlstream << cursor; | 240 | urlstream << cursor; |
563 | 241 | ||
564 | std::string url = urlstream.str(); | 242 | std::string url = urlstream.str(); |
565 | std::string response_data = get(*_oauth_client, url).perform(); | 243 | std::string response_data = get(auth_, url).perform(); |
566 | 244 | ||
567 | try | 245 | try |
568 | { | 246 | { |
@@ -604,7 +282,7 @@ namespace twitter { | |||
604 | urlstream << cursor; | 282 | urlstream << cursor; |
605 | 283 | ||
606 | std::string url = urlstream.str(); | 284 | std::string url = urlstream.str(); |
607 | std::string response_data = get(*_oauth_client, url).perform(); | 285 | std::string response_data = get(auth_, url).perform(); |
608 | 286 | ||
609 | try | 287 | try |
610 | { | 288 | { |
@@ -630,7 +308,7 @@ namespace twitter { | |||
630 | datastrstream << "follow=true&user_id="; | 308 | datastrstream << "follow=true&user_id="; |
631 | datastrstream << toFollow; | 309 | datastrstream << toFollow; |
632 | 310 | ||
633 | post(*_oauth_client, "https://api.twitter.com/1.1/friendships/create.json", datastrstream.str()).perform(); | 311 | post(auth_, "https://api.twitter.com/1.1/friendships/create.json", datastrstream.str()).perform(); |
634 | } | 312 | } |
635 | 313 | ||
636 | void client::follow(const user& toFollow) const | 314 | void client::follow(const user& toFollow) const |
@@ -644,7 +322,7 @@ namespace twitter { | |||
644 | datastrstream << "user_id="; | 322 | datastrstream << "user_id="; |
645 | datastrstream << toUnfollow; | 323 | datastrstream << toUnfollow; |
646 | 324 | ||
647 | post(*_oauth_client, "https://api.twitter.com/1.1/friendships/destroy.json", datastrstream.str()).perform(); | 325 | post(auth_, "https://api.twitter.com/1.1/friendships/destroy.json", datastrstream.str()).perform(); |
648 | } | 326 | } |
649 | 327 | ||
650 | void client::unfollow(const user& toUnfollow) const | 328 | void client::unfollow(const user& toUnfollow) const |
@@ -654,7 +332,7 @@ namespace twitter { | |||
654 | 332 | ||
655 | const user& client::getUser() const | 333 | const user& client::getUser() const |
656 | { | 334 | { |
657 | return *_current_user; | 335 | return currentUser_; |
658 | } | 336 | } |
659 | 337 | ||
660 | const configuration& client::getConfiguration() const | 338 | const configuration& client::getConfiguration() const |
@@ -662,8 +340,8 @@ namespace twitter { | |||
662 | if (!_configuration || (difftime(time(NULL), _last_configuration_update) > 60*60*24)) | 340 | if (!_configuration || (difftime(time(NULL), _last_configuration_update) > 60*60*24)) |
663 | { | 341 | { |
664 | _configuration = | 342 | _configuration = |
665 | make_unique<configuration>( | 343 | std::make_unique<configuration>( |
666 | get(*_oauth_client, | 344 | get(auth_, |
667 | "https://api.twitter.com/1.1/help/configuration.json") | 345 | "https://api.twitter.com/1.1/help/configuration.json") |
668 | .perform()); | 346 | .perform()); |
669 | 347 | ||
diff --git a/src/client.h b/src/client.h index 1e1b1ab..5e2ab1c 100644 --- a/src/client.h +++ b/src/client.h | |||
@@ -10,20 +10,14 @@ | |||
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(); | ||
27 | 21 | ||
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; |
@@ -51,18 +45,32 @@ namespace twitter { | |||
51 | 45 | ||
52 | const configuration& getConfiguration() const; | 46 | const configuration& getConfiguration() const; |
53 | 47 | ||
54 | private: | 48 | timeline& getHomeTimeline() |
49 | { | ||
50 | return homeTimeline_; | ||
51 | } | ||
55 | 52 | ||
56 | friend class stream; | 53 | timeline& getMentionsTimeline() |
54 | { | ||
55 | return mentionsTimeline_; | ||
56 | } | ||
57 | 57 | ||
58 | std::unique_ptr<OAuth::Consumer> _oauth_consumer; | 58 | private: |
59 | std::unique_ptr<OAuth::Token> _oauth_token; | ||
60 | std::unique_ptr<OAuth::Client> _oauth_client; | ||
61 | 59 | ||
62 | std::unique_ptr<user> _current_user; | 60 | const auth& auth_; |
61 | |||
62 | user currentUser_; | ||
63 | 63 | ||
64 | mutable std::unique_ptr<configuration> _configuration; | 64 | mutable std::unique_ptr<configuration> _configuration; |
65 | mutable time_t _last_configuration_update; | 65 | mutable time_t _last_configuration_update; |
66 | |||
67 | timeline homeTimeline_ { | ||
68 | auth_, | ||
69 | "https://api.twitter.com/1.1/statuses/home_timeline.json"}; | ||
70 | |||
71 | timeline mentionsTimeline_ { | ||
72 | auth_, | ||
73 | "https://api.twitter.com/1.1/statuses/mentions_timeline.json"}; | ||
66 | }; | 74 | }; |
67 | 75 | ||
68 | }; | 76 | }; |
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 */ |