diff options
| author | Kelly Rauchenberger <fefferburbia@gmail.com> | 2018-08-05 13:26:11 -0400 |
|---|---|---|
| committer | Kelly Rauchenberger <fefferburbia@gmail.com> | 2018-08-05 13:26:11 -0400 |
| commit | 9da997788ce89df755abc88896d0daec20bc2bdf (patch) | |
| tree | b0456c764ea3a44abe352300028faddcbaaeee53 | |
| parent | cf2323aa9ead54b05b8d0e04cef2bb7a5d0beba0 (diff) | |
| download | toldya-9da997788ce89df755abc88896d0daec20bc2bdf.tar.gz toldya-9da997788ce89df755abc88896d0daec20bc2bdf.tar.bz2 toldya-9da997788ce89df755abc88896d0daec20bc2bdf.zip | |
Switched from streaming API to timeline polling
| -rw-r--r-- | CMakeLists.txt | 2 | ||||
| -rw-r--r-- | toldya.cpp | 145 | ||||
| m--------- | vendor/libtwittercpp | 0 |
3 files changed, 52 insertions, 95 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( | |||
| 11 | ${yaml-cpp_INCLUDE_DIRS}) | 11 | ${yaml-cpp_INCLUDE_DIRS}) |
| 12 | 12 | ||
| 13 | add_executable(toldya toldya.cpp) | 13 | add_executable(toldya toldya.cpp) |
| 14 | set_property(TARGET toldya PROPERTY CXX_STANDARD 11) | 14 | set_property(TARGET toldya PROPERTY CXX_STANDARD 14) |
| 15 | set_property(TARGET toldya PROPERTY CXX_STANDARD_REQUIRED ON) | 15 | set_property(TARGET toldya PROPERTY CXX_STANDARD_REQUIRED ON) |
| 16 | target_link_libraries(toldya ${yaml-cpp_LIBRARIES} twitter++) | 16 | 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) | |||
| 22 | std::string configfile(argv[1]); | 22 | std::string configfile(argv[1]); |
| 23 | YAML::Node config = YAML::LoadFile(configfile); | 23 | YAML::Node config = YAML::LoadFile(configfile); |
| 24 | 24 | ||
| 25 | twitter::auth auth; | 25 | twitter::auth auth( |
| 26 | auth.setConsumerKey(config["consumer_key"].as<std::string>()); | 26 | config["consumer_key"].as<std::string>(), |
| 27 | auth.setConsumerSecret(config["consumer_secret"].as<std::string>()); | 27 | config["consumer_secret"].as<std::string>(), |
| 28 | auth.setAccessKey(config["access_key"].as<std::string>()); | 28 | config["access_key"].as<std::string>(), |
| 29 | auth.setAccessSecret(config["access_secret"].as<std::string>()); | 29 | config["access_secret"].as<std::string>()); |
| 30 | 30 | ||
| 31 | std::vector<std::string> captions { | 31 | std::vector<std::string> captions { |
| 32 | "It begins.", | 32 | "It begins.", |
| @@ -36,117 +36,62 @@ int main(int argc, char** argv) | |||
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| 38 | std::map<twitter::user_id, std::vector<twitter::tweet>> potential; | 38 | std::map<twitter::user_id, std::vector<twitter::tweet>> potential; |
| 39 | std::set<twitter::tweet_id> deletions; | 39 | std::set<twitter::tweet_id> tweetIds; |
| 40 | std::mutex potentialMutex; | ||
| 41 | 40 | ||
| 42 | twitter::client client(auth); | 41 | twitter::client client(auth); |
| 43 | std::set<twitter::user_id> streamedFriends; | 42 | std::set<twitter::user_id> friends = client.getFriends(); |
| 44 | 43 | ||
| 45 | std::cout << "Starting streaming" << std::endl; | 44 | for (;;) |
| 45 | { | ||
| 46 | // Poll every 5 minutes | ||
| 47 | auto midtime = time(NULL); | ||
| 48 | auto midtm = localtime(&midtime); | ||
| 46 | 49 | ||
| 47 | twitter::stream userStream(client, [&] (twitter::notification n) { | 50 | // At 9am, do the daily tweet |
| 48 | if (n.getType() == twitter::notification::type::friends) | 51 | bool shouldTweet = false; |
| 49 | { | 52 | if (midtm->tm_hour == 8 && midtm->tm_min >= 55) |
| 50 | streamedFriends = n.getFriends(); | ||
| 51 | } else if (n.getType() == twitter::notification::type::follow) | ||
| 52 | { | 53 | { |
| 53 | streamedFriends.insert(n.getUser().getID()); | 54 | shouldTweet = true; |
| 54 | } else if (n.getType() == twitter::notification::type::unfollow) | 55 | |
| 55 | { | 56 | std::cout << "Sleeping for 5 minutes (will tweet)..." << std::endl; |
| 56 | streamedFriends.erase(n.getUser().getID()); | 57 | } else { |
| 57 | } else if (n.getType() == twitter::notification::type::tweet) | 58 | std::cout << "Sleeping for 5 minutes..." << std::endl; |
| 59 | } | ||
| 60 | |||
| 61 | std::this_thread::sleep_for(std::chrono::minutes(5)); | ||
| 62 | |||
| 63 | std::list<twitter::tweet> newTweets = client.getHomeTimeline().poll(); | ||
| 64 | for (twitter::tweet& nt : newTweets) | ||
| 58 | { | 65 | { |
| 59 | // Only monitor people you are following | 66 | // Only monitor people you are following |
| 60 | // Ignore retweets | 67 | // Ignore retweets |
| 61 | // Ignore messages | 68 | // Ignore messages |
| 62 | if ( | 69 | if ( |
| 63 | (streamedFriends.count(n.getTweet().getAuthor().getID()) == 1) | 70 | (friends.count(nt.getAuthor().getID()) == 1) |
| 64 | && (!n.getTweet().isRetweet()) | 71 | && (!nt.isRetweet()) |
| 65 | && (n.getTweet().getText().front() != '@') | 72 | && (nt.getText().front() != '@') |
| 66 | ) | 73 | ) |
| 67 | { | 74 | { |
| 68 | std::lock_guard<std::mutex> potentialGuard(potentialMutex); | 75 | std::cout << nt.getID() << ": " << nt.getText() << std::endl; |
| 69 | std::cout << n.getTweet().getID() << ": " << n.getTweet().getText() | ||
| 70 | << std::endl; | ||
| 71 | 76 | ||
| 72 | potential[n.getTweet().getAuthor().getID()]. | 77 | tweetIds.insert(nt.getID()); |
| 73 | push_back(std::move(n.getTweet())); | 78 | potential[nt.getAuthor().getID()].emplace_back(std::move(nt)); |
| 74 | } | ||
| 75 | } else if (n.getType() == twitter::notification::type::followed) | ||
| 76 | { | ||
| 77 | try | ||
| 78 | { | ||
| 79 | client.follow(n.getUser()); | ||
| 80 | } catch (const twitter::twitter_error& error) | ||
| 81 | { | ||
| 82 | std::cout << "Twitter error while following @" | ||
| 83 | << n.getUser().getScreenName() << ": " << error.what() << std::endl; | ||
| 84 | } | 79 | } |
| 85 | } else if (n.getType() == twitter::notification::type::deletion) | ||
| 86 | { | ||
| 87 | std::lock_guard<std::mutex> potentialGuard(potentialMutex); | ||
| 88 | std::cout << "Tweet " << n.getTweetID() << " was deleted." << std::endl; | ||
| 89 | |||
| 90 | deletions.insert(n.getTweetID()); | ||
| 91 | } | 80 | } |
| 92 | }); | ||
| 93 | 81 | ||
| 94 | std::this_thread::sleep_for(std::chrono::minutes(1)); | 82 | newTweets.clear(); |
| 95 | 83 | ||
| 96 | for (;;) | 84 | // The rest of the loop is once-a-day |
| 97 | { | 85 | if (!shouldTweet) |
| 98 | // Wait until 9am | ||
| 99 | auto midtime = time(NULL); | ||
| 100 | auto midtm = localtime(&midtime); | ||
| 101 | midtm->tm_hour = 0; | ||
| 102 | midtm->tm_min = 0; | ||
| 103 | midtm->tm_sec = 0; | ||
| 104 | auto to_until = std::chrono::system_clock::from_time_t(std::mktime(midtm)); | ||
| 105 | auto to_wait = std::chrono::duration_cast<std::chrono::seconds>( | ||
| 106 | (to_until + std::chrono::hours(24 + 9)) | ||
| 107 | - std::chrono::system_clock::now()); | ||
| 108 | |||
| 109 | int waitlen = to_wait.count(); | ||
| 110 | if (waitlen == 0) | ||
| 111 | { | 86 | { |
| 112 | continue; | 87 | continue; |
| 113 | } else if (waitlen == 1) | ||
| 114 | { | ||
| 115 | std::cout << "Sleeping for 1 second..." << std::endl; | ||
| 116 | } else if (waitlen < 60) | ||
| 117 | { | ||
| 118 | std::cout << "Sleeping for " << waitlen << " seconds..." << std::endl; | ||
| 119 | } else if (waitlen == 60) | ||
| 120 | { | ||
| 121 | std::cout << "Sleeping for 1 minute..." << std::endl; | ||
| 122 | } else if (waitlen < 60*60) | ||
| 123 | { | ||
| 124 | std::cout << "Sleeping for " << (waitlen/60) << " minutes..." | ||
| 125 | << std::endl; | ||
| 126 | } else if (waitlen == 60*60) | ||
| 127 | { | ||
| 128 | std::cout << "Sleeping for 1 hour..." << std::endl; | ||
| 129 | } else if (waitlen < 60*60*24) | ||
| 130 | { | ||
| 131 | std::cout << "Sleeping for " << (waitlen/60/60) << " hours..." | ||
| 132 | << std::endl; | ||
| 133 | } else if (waitlen == 60*60*24) | ||
| 134 | { | ||
| 135 | std::cout << "Sleeping for 1 day..." << std::endl; | ||
| 136 | } else { | ||
| 137 | std::cout << "Sleeping for " << (waitlen/60/60/24) << " days..." | ||
| 138 | << std::endl; | ||
| 139 | } | 88 | } |
| 140 | 89 | ||
| 141 | std::this_thread::sleep_for(to_wait); | ||
| 142 | |||
| 143 | // The rest of the loop deals with the potential tweets | ||
| 144 | std::lock_guard<std::mutex> potentialGuard(potentialMutex); | ||
| 145 | |||
| 146 | // Unfollow people who have unfollowed us | 90 | // Unfollow people who have unfollowed us |
| 147 | try | 91 | try |
| 148 | { | 92 | { |
| 149 | std::set<twitter::user_id> friends = client.getFriends(); | 93 | friends = client.getFriends(); |
| 94 | |||
| 150 | std::set<twitter::user_id> followers = client.getFollowers(); | 95 | std::set<twitter::user_id> followers = client.getFollowers(); |
| 151 | 96 | ||
| 152 | std::list<twitter::user_id> oldFriends; | 97 | std::list<twitter::user_id> oldFriends; |
| @@ -192,6 +137,19 @@ int main(int argc, char** argv) | |||
| 192 | } | 137 | } |
| 193 | } | 138 | } |
| 194 | 139 | ||
| 140 | // Hydrate the tweets we've received to make sure that none of them have | ||
| 141 | // been deleted. | ||
| 142 | std::list<twitter::tweet> hydrated = client.hydrateTweets(tweetIds); | ||
| 143 | tweetIds.clear(); | ||
| 144 | |||
| 145 | std::set<twitter::tweet_id> hydratedIds; | ||
| 146 | for (twitter::tweet& tw : hydrated) | ||
| 147 | { | ||
| 148 | hydratedIds.insert(tw.getID()); | ||
| 149 | } | ||
| 150 | |||
| 151 | hydrated.clear(); | ||
| 152 | |||
| 195 | // Filter the potential tweets for users that are still following us, and | 153 | // Filter the potential tweets for users that are still following us, and |
| 196 | // and for tweets that haven't been deleted. | 154 | // and for tweets that haven't been deleted. |
| 197 | std::map<twitter::user_id, std::vector<twitter::tweet>> toKeep; | 155 | std::map<twitter::user_id, std::vector<twitter::tweet>> toKeep; |
| @@ -206,7 +164,7 @@ int main(int argc, char** argv) | |||
| 206 | for (twitter::tweet& pt : p.second) | 164 | for (twitter::tweet& pt : p.second) |
| 207 | { | 165 | { |
| 208 | // The tweet was not deleted | 166 | // The tweet was not deleted |
| 209 | if (!deletions.count(pt.getID())) | 167 | if (hydratedIds.count(pt.getID())) |
| 210 | { | 168 | { |
| 211 | userTweets.push_back(std::move(pt)); | 169 | userTweets.push_back(std::move(pt)); |
| 212 | } | 170 | } |
| @@ -220,7 +178,6 @@ int main(int argc, char** argv) | |||
| 220 | } | 178 | } |
| 221 | 179 | ||
| 222 | potential = std::move(toKeep); | 180 | potential = std::move(toKeep); |
| 223 | deletions.clear(); | ||
| 224 | } catch (const twitter::twitter_error& error) | 181 | } catch (const twitter::twitter_error& error) |
| 225 | { | 182 | { |
| 226 | std::cout << "Twitter error while getting friends/followers: " | 183 | std::cout << "Twitter error while getting friends/followers: " |
| diff --git a/vendor/libtwittercpp b/vendor/libtwittercpp | |||
| Subproject 7c44fd17bb6be54a2ea4b60761e91053ca98897 | Subproject 204181c5654cee745b6b1ba98675609e784f0ee | ||
