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