summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2018-08-05 13:26:11 -0400
committerKelly Rauchenberger <fefferburbia@gmail.com>2018-08-05 13:26:11 -0400
commit9da997788ce89df755abc88896d0daec20bc2bdf (patch)
treeb0456c764ea3a44abe352300028faddcbaaeee53
parentcf2323aa9ead54b05b8d0e04cef2bb7a5d0beba0 (diff)
downloadtoldya-9da997788ce89df755abc88896d0daec20bc2bdf.tar.gz
toldya-9da997788ce89df755abc88896d0daec20bc2bdf.tar.bz2
toldya-9da997788ce89df755abc88896d0daec20bc2bdf.zip
Switched from streaming API to timeline polling
-rw-r--r--CMakeLists.txt2
-rw-r--r--toldya.cpp145
m---------vendor/libtwittercpp0
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
13add_executable(toldya toldya.cpp) 13add_executable(toldya toldya.cpp)
14set_property(TARGET toldya PROPERTY CXX_STANDARD 11) 14set_property(TARGET toldya PROPERTY CXX_STANDARD 14)
15set_property(TARGET toldya PROPERTY CXX_STANDARD_REQUIRED ON) 15set_property(TARGET toldya PROPERTY CXX_STANDARD_REQUIRED ON)
16target_link_libraries(toldya ${yaml-cpp_LIBRARIES} twitter++) 16target_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