From 9da997788ce89df755abc88896d0daec20bc2bdf Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Sun, 5 Aug 2018 13:26:11 -0400 Subject: Switched from streaming API to timeline polling --- CMakeLists.txt | 2 +- toldya.cpp | 145 ++++++++++++++++++--------------------------------- vendor/libtwittercpp | 2 +- 3 files changed, 53 insertions(+), 96 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bd250a3..88ab63a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,6 @@ include_directories( ${yaml-cpp_INCLUDE_DIRS}) add_executable(toldya toldya.cpp) -set_property(TARGET toldya PROPERTY CXX_STANDARD 11) +set_property(TARGET toldya PROPERTY CXX_STANDARD 14) set_property(TARGET toldya PROPERTY CXX_STANDARD_REQUIRED ON) target_link_libraries(toldya ${yaml-cpp_LIBRARIES} twitter++) diff --git a/toldya.cpp b/toldya.cpp index a5e7172..55f00a8 100644 --- a/toldya.cpp +++ b/toldya.cpp @@ -22,11 +22,11 @@ int main(int argc, char** argv) std::string configfile(argv[1]); YAML::Node config = YAML::LoadFile(configfile); - twitter::auth auth; - auth.setConsumerKey(config["consumer_key"].as()); - auth.setConsumerSecret(config["consumer_secret"].as()); - auth.setAccessKey(config["access_key"].as()); - auth.setAccessSecret(config["access_secret"].as()); + twitter::auth auth( + config["consumer_key"].as(), + config["consumer_secret"].as(), + config["access_key"].as(), + config["access_secret"].as()); std::vector captions { "It begins.", @@ -36,117 +36,62 @@ int main(int argc, char** argv) }; std::map> potential; - std::set deletions; - std::mutex potentialMutex; + std::set tweetIds; twitter::client client(auth); - std::set streamedFriends; + std::set friends = client.getFriends(); - std::cout << "Starting streaming" << std::endl; + for (;;) + { + // Poll every 5 minutes + auto midtime = time(NULL); + auto midtm = localtime(&midtime); - twitter::stream userStream(client, [&] (twitter::notification n) { - if (n.getType() == twitter::notification::type::friends) - { - streamedFriends = n.getFriends(); - } else if (n.getType() == twitter::notification::type::follow) + // At 9am, do the daily tweet + bool shouldTweet = false; + if (midtm->tm_hour == 8 && midtm->tm_min >= 55) { - streamedFriends.insert(n.getUser().getID()); - } else if (n.getType() == twitter::notification::type::unfollow) - { - streamedFriends.erase(n.getUser().getID()); - } else if (n.getType() == twitter::notification::type::tweet) + shouldTweet = true; + + std::cout << "Sleeping for 5 minutes (will tweet)..." << std::endl; + } else { + std::cout << "Sleeping for 5 minutes..." << std::endl; + } + + std::this_thread::sleep_for(std::chrono::minutes(5)); + + std::list newTweets = client.getHomeTimeline().poll(); + for (twitter::tweet& nt : newTweets) { // Only monitor people you are following // Ignore retweets // Ignore messages if ( - (streamedFriends.count(n.getTweet().getAuthor().getID()) == 1) - && (!n.getTweet().isRetweet()) - && (n.getTweet().getText().front() != '@') + (friends.count(nt.getAuthor().getID()) == 1) + && (!nt.isRetweet()) + && (nt.getText().front() != '@') ) { - std::lock_guard potentialGuard(potentialMutex); - std::cout << n.getTweet().getID() << ": " << n.getTweet().getText() - << std::endl; + std::cout << nt.getID() << ": " << nt.getText() << std::endl; - potential[n.getTweet().getAuthor().getID()]. - push_back(std::move(n.getTweet())); - } - } else if (n.getType() == twitter::notification::type::followed) - { - try - { - client.follow(n.getUser()); - } catch (const twitter::twitter_error& error) - { - std::cout << "Twitter error while following @" - << n.getUser().getScreenName() << ": " << error.what() << std::endl; + tweetIds.insert(nt.getID()); + potential[nt.getAuthor().getID()].emplace_back(std::move(nt)); } - } else if (n.getType() == twitter::notification::type::deletion) - { - std::lock_guard potentialGuard(potentialMutex); - std::cout << "Tweet " << n.getTweetID() << " was deleted." << std::endl; - - deletions.insert(n.getTweetID()); } - }); - std::this_thread::sleep_for(std::chrono::minutes(1)); + newTweets.clear(); - for (;;) - { - // Wait until 9am - auto midtime = time(NULL); - auto midtm = localtime(&midtime); - midtm->tm_hour = 0; - midtm->tm_min = 0; - midtm->tm_sec = 0; - auto to_until = std::chrono::system_clock::from_time_t(std::mktime(midtm)); - auto to_wait = std::chrono::duration_cast( - (to_until + std::chrono::hours(24 + 9)) - - std::chrono::system_clock::now()); - - int waitlen = to_wait.count(); - if (waitlen == 0) + // The rest of the loop is once-a-day + if (!shouldTweet) { continue; - } else if (waitlen == 1) - { - std::cout << "Sleeping for 1 second..." << std::endl; - } else if (waitlen < 60) - { - std::cout << "Sleeping for " << waitlen << " seconds..." << std::endl; - } else if (waitlen == 60) - { - std::cout << "Sleeping for 1 minute..." << std::endl; - } else if (waitlen < 60*60) - { - std::cout << "Sleeping for " << (waitlen/60) << " minutes..." - << std::endl; - } else if (waitlen == 60*60) - { - std::cout << "Sleeping for 1 hour..." << std::endl; - } else if (waitlen < 60*60*24) - { - std::cout << "Sleeping for " << (waitlen/60/60) << " hours..." - << std::endl; - } else if (waitlen == 60*60*24) - { - std::cout << "Sleeping for 1 day..." << std::endl; - } else { - std::cout << "Sleeping for " << (waitlen/60/60/24) << " days..." - << std::endl; } - std::this_thread::sleep_for(to_wait); - - // The rest of the loop deals with the potential tweets - std::lock_guard potentialGuard(potentialMutex); - // Unfollow people who have unfollowed us try { - std::set friends = client.getFriends(); + friends = client.getFriends(); + std::set followers = client.getFollowers(); std::list oldFriends; @@ -192,6 +137,19 @@ int main(int argc, char** argv) } } + // Hydrate the tweets we've received to make sure that none of them have + // been deleted. + std::list hydrated = client.hydrateTweets(tweetIds); + tweetIds.clear(); + + std::set hydratedIds; + for (twitter::tweet& tw : hydrated) + { + hydratedIds.insert(tw.getID()); + } + + hydrated.clear(); + // Filter the potential tweets for users that are still following us, and // and for tweets that haven't been deleted. std::map> toKeep; @@ -206,7 +164,7 @@ int main(int argc, char** argv) for (twitter::tweet& pt : p.second) { // The tweet was not deleted - if (!deletions.count(pt.getID())) + if (hydratedIds.count(pt.getID())) { userTweets.push_back(std::move(pt)); } @@ -220,7 +178,6 @@ int main(int argc, char** argv) } potential = std::move(toKeep); - deletions.clear(); } catch (const twitter::twitter_error& error) { std::cout << "Twitter error while getting friends/followers: " diff --git a/vendor/libtwittercpp b/vendor/libtwittercpp index 7c44fd1..204181c 160000 --- a/vendor/libtwittercpp +++ b/vendor/libtwittercpp @@ -1 +1 @@ -Subproject commit 7c44fd17bb6be54a2ea4b60761e91053ca988977 +Subproject commit 204181c5654cee745b6b1ba98675609e784f0ee1 -- cgit 1.4.1