diff options
author | Kelly Rauchenberger <fefferburbia@gmail.com> | 2018-08-05 11:14:39 -0400 |
---|---|---|
committer | Kelly Rauchenberger <fefferburbia@gmail.com> | 2018-08-05 11:14:39 -0400 |
commit | 38203b745ae1903ba0804ed5532b78d255bea635 (patch) | |
tree | 52f57ce85e65361c534c461abc82fb1ed9768d49 /src | |
parent | 7c44fd17bb6be54a2ea4b60761e91053ca988977 (diff) | |
download | libtwittercpp-38203b745ae1903ba0804ed5532b78d255bea635.tar.gz libtwittercpp-38203b745ae1903ba0804ed5532b78d255bea635.tar.bz2 libtwittercpp-38203b745ae1903ba0804ed5532b78d255bea635.zip |
Added timeline polling
Because the streaming API will sunset on August 16th, it is essential to implement timeline polling so that the library can still be used to access tweets. This commit breaks the current API even for clients still using the streaming API because the OAuth connection data was pulled from twitter::client into twitter::auth. Other than that, almost everything works the same, and if a client wants to update their libtwitter++ within the next week and a half, they are free to.
Diffstat (limited to 'src')
-rw-r--r-- | src/auth.cpp | 45 | ||||
-rw-r--r-- | src/auth.h | 44 | ||||
-rw-r--r-- | src/client.cpp | 460 | ||||
-rw-r--r-- | src/client.h | 66 | ||||
-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, 920 insertions, 820 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 e16e30b..820db80 100644 --- a/src/client.cpp +++ b/src/client.cpp | |||
@@ -2,385 +2,65 @@ | |||
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 | |||
85 | class request | ||
86 | { | ||
87 | public: | ||
88 | |||
89 | explicit request(std::string url) try | ||
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 | 10 | ||
181 | if (response_code == 429) | 11 | client::client( |
182 | { | 12 | const auth& _arg) : |
183 | throw rate_limit_exceeded("HTTP 429 Too Many Requests"); | 13 | auth_(_arg), |
184 | } else if (response_code == 500) | 14 | currentUser_( |
185 | { | 15 | get(auth_, |
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; |
344 | datastrstream << "status=" << OAuth::PercentEncode(msg); | 24 | datastrstream << "status=" << OAuth::PercentEncode(msg); |
345 | 25 | ||
346 | if (!media_ids.empty()) | 26 | if (!media_ids.empty()) |
347 | { | 27 | { |
348 | datastrstream << "&media_ids="; | 28 | datastrstream << "&media_ids="; |
349 | datastrstream << twitter::implode(std::begin(media_ids), std::end(media_ids), ","); | 29 | datastrstream << twitter::implode(std::begin(media_ids), std::end(media_ids), ","); |
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()); |
357 | } | 37 | } |
358 | 38 | ||
359 | tweet client::replyToTweet(std::string msg, tweet_id in_response_to, std::list<long> media_ids) const | 39 | tweet client::replyToTweet(std::string msg, tweet_id in_response_to, std::list<long> media_ids) const |
360 | { | 40 | { |
361 | std::stringstream datastrstream; | 41 | std::stringstream datastrstream; |
362 | datastrstream << "status=" << OAuth::PercentEncode(msg); | 42 | datastrstream << "status=" << OAuth::PercentEncode(msg); |
363 | datastrstream << "&in_reply_to_status_id="; | 43 | datastrstream << "&in_reply_to_status_id="; |
364 | datastrstream << in_response_to; | 44 | datastrstream << in_response_to; |
365 | 45 | ||
366 | if (!media_ids.empty()) | 46 | if (!media_ids.empty()) |
367 | { | 47 | { |
368 | datastrstream << "&media_ids="; | 48 | datastrstream << "&media_ids="; |
369 | datastrstream << twitter::implode(std::begin(media_ids), std::end(media_ids), ","); | 49 | datastrstream << twitter::implode(std::begin(media_ids), std::end(media_ids), ","); |
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()); |
377 | } | 57 | } |
378 | 58 | ||
379 | long client::uploadMedia(std::string media_type, const char* data, long data_length) const try | 59 | long client::uploadMedia(std::string media_type, const char* data, long data_length) const try |
380 | { | 60 | { |
381 | curl::curl_form form; | 61 | curl::curl_form form; |
382 | std::string str_data_length = std::to_string(data_length); | 62 | std::string str_data_length = std::to_string(data_length); |
383 | 63 | ||
384 | curl::curl_pair<CURLformoption, std::string> command_name(CURLFORM_COPYNAME, "command"); | 64 | curl::curl_pair<CURLformoption, std::string> command_name(CURLFORM_COPYNAME, "command"); |
385 | curl::curl_pair<CURLformoption, std::string> command_cont(CURLFORM_COPYCONTENTS, "INIT"); | 65 | curl::curl_pair<CURLformoption, std::string> command_cont(CURLFORM_COPYCONTENTS, "INIT"); |
386 | curl::curl_pair<CURLformoption, std::string> bytes_name(CURLFORM_COPYNAME, "total_bytes"); | 66 | curl::curl_pair<CURLformoption, std::string> bytes_name(CURLFORM_COPYNAME, "total_bytes"); |
@@ -397,15 +77,15 @@ namespace twitter { | |||
397 | curl::curl_pair<CURLformoption, std::string> category_cont(CURLFORM_COPYCONTENTS, "tweet_gif"); | 77 | curl::curl_pair<CURLformoption, std::string> category_cont(CURLFORM_COPYCONTENTS, "tweet_gif"); |
398 | form.add(category_name, category_cont); | 78 | form.add(category_name, category_cont); |
399 | } | 79 | } |
400 | 80 | ||
401 | std::string init_response = | 81 | std::string init_response = |
402 | multipost(*_oauth_client, | 82 | multipost(auth_, |
403 | "https://upload.twitter.com/1.1/media/upload.json", | 83 | "https://upload.twitter.com/1.1/media/upload.json", |
404 | form.get()) | 84 | form.get()) |
405 | .perform(); | 85 | .perform(); |
406 | 86 | ||
407 | long media_id; | 87 | long media_id; |
408 | 88 | ||
409 | try | 89 | try |
410 | { | 90 | { |
411 | nlohmann::json response_json = nlohmann::json::parse(init_response); | 91 | nlohmann::json response_json = nlohmann::json::parse(init_response); |
@@ -429,29 +109,29 @@ namespace twitter { | |||
429 | { | 109 | { |
430 | assert(false); | 110 | assert(false); |
431 | } | 111 | } |
432 | 112 | ||
433 | multipost(*_oauth_client, "https://upload.twitter.com/1.1/media/upload.json", append_form_post).perform(); | 113 | multipost(auth_, "https://upload.twitter.com/1.1/media/upload.json", append_form_post).perform(); |
434 | 114 | ||
435 | curl_formfree(append_form_post); | 115 | curl_formfree(append_form_post); |
436 | 116 | ||
437 | curl::curl_form finalize_form; | 117 | curl::curl_form finalize_form; |
438 | std::string str_media_id = std::to_string(media_id); | 118 | std::string str_media_id = std::to_string(media_id); |
439 | 119 | ||
440 | curl::curl_pair<CURLformoption, std::string> command3_name(CURLFORM_COPYNAME, "command"); | 120 | curl::curl_pair<CURLformoption, std::string> command3_name(CURLFORM_COPYNAME, "command"); |
441 | curl::curl_pair<CURLformoption, std::string> command3_cont(CURLFORM_COPYCONTENTS, "FINALIZE"); | 121 | curl::curl_pair<CURLformoption, std::string> command3_cont(CURLFORM_COPYCONTENTS, "FINALIZE"); |
442 | curl::curl_pair<CURLformoption, std::string> media_id_name(CURLFORM_COPYNAME, "media_id"); | 122 | curl::curl_pair<CURLformoption, std::string> media_id_name(CURLFORM_COPYNAME, "media_id"); |
443 | curl::curl_pair<CURLformoption, std::string> media_id_cont(CURLFORM_COPYCONTENTS, str_media_id); | 123 | curl::curl_pair<CURLformoption, std::string> media_id_cont(CURLFORM_COPYCONTENTS, str_media_id); |
444 | finalize_form.add(command3_name, command3_cont); | 124 | finalize_form.add(command3_name, command3_cont); |
445 | finalize_form.add(media_id_name, media_id_cont); | 125 | finalize_form.add(media_id_name, media_id_cont); |
446 | 126 | ||
447 | std::string finalize_response = | 127 | std::string finalize_response = |
448 | multipost(*_oauth_client, | 128 | multipost(auth_, |
449 | "https://upload.twitter.com/1.1/media/upload.json", | 129 | "https://upload.twitter.com/1.1/media/upload.json", |
450 | finalize_form.get()) | 130 | finalize_form.get()) |
451 | .perform(); | 131 | .perform(); |
452 | 132 | ||
453 | nlohmann::json finalize_json; | 133 | nlohmann::json finalize_json; |
454 | 134 | ||
455 | try | 135 | try |
456 | { | 136 | { |
457 | finalize_json = nlohmann::json::parse(finalize_response); | 137 | finalize_json = nlohmann::json::parse(finalize_response); |
@@ -459,26 +139,26 @@ namespace twitter { | |||
459 | { | 139 | { |
460 | std::throw_with_nested(invalid_response(finalize_response)); | 140 | std::throw_with_nested(invalid_response(finalize_response)); |
461 | } | 141 | } |
462 | 142 | ||
463 | if (finalize_json.find("processing_info") != finalize_json.end()) | 143 | if (finalize_json.find("processing_info") != finalize_json.end()) |
464 | { | 144 | { |
465 | std::stringstream datastr; | 145 | std::stringstream datastr; |
466 | datastr << "https://upload.twitter.com/1.1/media/upload.json?command=STATUS&media_id=" << media_id; | 146 | datastr << "https://upload.twitter.com/1.1/media/upload.json?command=STATUS&media_id=" << media_id; |
467 | 147 | ||
468 | for (;;) | 148 | for (;;) |
469 | { | 149 | { |
470 | std::string status_response = get(*_oauth_client, datastr.str()).perform(); | 150 | std::string status_response = get(auth_, datastr.str()).perform(); |
471 | 151 | ||
472 | try | 152 | try |
473 | { | 153 | { |
474 | nlohmann::json status_json = nlohmann::json::parse(status_response); | 154 | nlohmann::json status_json = nlohmann::json::parse(status_response); |
475 | std::string state = status_json["processing_info"]["state"].get<std::string>(); | 155 | std::string state = status_json["processing_info"]["state"].get<std::string>(); |
476 | 156 | ||
477 | if (state == "succeeded") | 157 | if (state == "succeeded") |
478 | { | 158 | { |
479 | break; | 159 | break; |
480 | } | 160 | } |
481 | 161 | ||
482 | int ttw = status_json["processing_info"]["check_after_secs"].get<int>(); | 162 | int ttw = status_json["processing_info"]["check_after_secs"].get<int>(); |
483 | std::this_thread::sleep_for(std::chrono::seconds(ttw)); | 163 | std::this_thread::sleep_for(std::chrono::seconds(ttw)); |
484 | } catch (const std::invalid_argument& error) | 164 | } catch (const std::invalid_argument& error) |
@@ -490,20 +170,18 @@ namespace twitter { | |||
490 | } | 170 | } |
491 | } | 171 | } |
492 | } | 172 | } |
493 | 173 | ||
494 | return media_id; | 174 | return media_id; |
495 | } catch (const curl::curl_exception& error) | 175 | } catch (const curl::curl_exception& error) |
496 | { | 176 | { |
497 | error.print_traceback(); | 177 | std::throw_with_nested(connection_error()); |
498 | |||
499 | assert(false); | ||
500 | } | 178 | } |
501 | 179 | ||
502 | std::set<user_id> client::getFriends(user_id id) const | 180 | std::set<user_id> client::getFriends(user_id id) const |
503 | { | 181 | { |
504 | long long cursor = -1; | 182 | long long cursor = -1; |
505 | std::set<user_id> result; | 183 | std::set<user_id> result; |
506 | 184 | ||
507 | while (cursor != 0) | 185 | while (cursor != 0) |
508 | { | 186 | { |
509 | std::stringstream urlstream; | 187 | std::stringstream urlstream; |
@@ -511,14 +189,14 @@ namespace twitter { | |||
511 | urlstream << id; | 189 | urlstream << id; |
512 | urlstream << "&cursor="; | 190 | urlstream << "&cursor="; |
513 | urlstream << cursor; | 191 | urlstream << cursor; |
514 | 192 | ||
515 | std::string url = urlstream.str(); | 193 | std::string url = urlstream.str(); |
516 | std::string response_data = get(*_oauth_client, url).perform(); | 194 | std::string response_data = get(auth_, url).perform(); |
517 | 195 | ||
518 | try | 196 | try |
519 | { | 197 | { |
520 | nlohmann::json rjs = nlohmann::json::parse(response_data); | 198 | nlohmann::json rjs = nlohmann::json::parse(response_data); |
521 | 199 | ||
522 | cursor = rjs["next_cursor"].get<long long>(); | 200 | cursor = rjs["next_cursor"].get<long long>(); |
523 | result.insert(std::begin(rjs["ids"]), std::end(rjs["ids"])); | 201 | result.insert(std::begin(rjs["ids"]), std::end(rjs["ids"])); |
524 | } catch (const std::invalid_argument& error) | 202 | } catch (const std::invalid_argument& error) |
@@ -529,25 +207,25 @@ namespace twitter { | |||
529 | std::throw_with_nested(invalid_response(response_data)); | 207 | std::throw_with_nested(invalid_response(response_data)); |
530 | } | 208 | } |
531 | } | 209 | } |
532 | 210 | ||
533 | return result; | 211 | return result; |
534 | } | 212 | } |
535 | 213 | ||
536 | std::set<user_id> client::getFriends(const user& id) const | 214 | std::set<user_id> client::getFriends(const user& id) const |
537 | { | 215 | { |
538 | return getFriends(id.getID()); | 216 | return getFriends(id.getID()); |
539 | } | 217 | } |
540 | 218 | ||
541 | std::set<user_id> client::getFriends() const | 219 | std::set<user_id> client::getFriends() const |
542 | { | 220 | { |
543 | return getFriends(getUser().getID()); | 221 | return getFriends(getUser().getID()); |
544 | } | 222 | } |
545 | 223 | ||
546 | std::set<user_id> client::getFollowers(user_id id) const | 224 | std::set<user_id> client::getFollowers(user_id id) const |
547 | { | 225 | { |
548 | long long cursor = -1; | 226 | long long cursor = -1; |
549 | std::set<user_id> result; | 227 | std::set<user_id> result; |
550 | 228 | ||
551 | while (cursor != 0) | 229 | while (cursor != 0) |
552 | { | 230 | { |
553 | std::stringstream urlstream; | 231 | std::stringstream urlstream; |
@@ -555,14 +233,14 @@ namespace twitter { | |||
555 | urlstream << id; | 233 | urlstream << id; |
556 | urlstream << "&cursor="; | 234 | urlstream << "&cursor="; |
557 | urlstream << cursor; | 235 | urlstream << cursor; |
558 | 236 | ||
559 | std::string url = urlstream.str(); | 237 | std::string url = urlstream.str(); |
560 | std::string response_data = get(*_oauth_client, url).perform(); | 238 | std::string response_data = get(auth_, url).perform(); |
561 | 239 | ||
562 | try | 240 | try |
563 | { | 241 | { |
564 | nlohmann::json rjs = nlohmann::json::parse(response_data); | 242 | nlohmann::json rjs = nlohmann::json::parse(response_data); |
565 | 243 | ||
566 | cursor = rjs["next_cursor"].get<long long>(); | 244 | cursor = rjs["next_cursor"].get<long long>(); |
567 | result.insert(std::begin(rjs["ids"]), std::end(rjs["ids"])); | 245 | result.insert(std::begin(rjs["ids"]), std::end(rjs["ids"])); |
568 | } catch (const std::invalid_argument& error) | 246 | } catch (const std::invalid_argument& error) |
@@ -573,43 +251,43 @@ namespace twitter { | |||
573 | std::throw_with_nested(invalid_response(response_data)); | 251 | std::throw_with_nested(invalid_response(response_data)); |
574 | } | 252 | } |
575 | } | 253 | } |
576 | 254 | ||
577 | return result; | 255 | return result; |
578 | } | 256 | } |
579 | 257 | ||
580 | std::set<user_id> client::getFollowers(const user& id) const | 258 | std::set<user_id> client::getFollowers(const user& id) const |
581 | { | 259 | { |
582 | return getFollowers(id.getID()); | 260 | return getFollowers(id.getID()); |
583 | } | 261 | } |
584 | 262 | ||
585 | std::set<user_id> client::getFollowers() const | 263 | std::set<user_id> client::getFollowers() const |
586 | { | 264 | { |
587 | return getFollowers(getUser().getID()); | 265 | return getFollowers(getUser().getID()); |
588 | } | 266 | } |
589 | 267 | ||
590 | void client::follow(user_id toFollow) const | 268 | void client::follow(user_id toFollow) const |
591 | { | 269 | { |
592 | std::stringstream datastrstream; | 270 | std::stringstream datastrstream; |
593 | datastrstream << "follow=true&user_id="; | 271 | datastrstream << "follow=true&user_id="; |
594 | datastrstream << toFollow; | 272 | datastrstream << toFollow; |
595 | 273 | ||
596 | post(*_oauth_client, "https://api.twitter.com/1.1/friendships/create.json", datastrstream.str()).perform(); | 274 | post(auth_, "https://api.twitter.com/1.1/friendships/create.json", datastrstream.str()).perform(); |
597 | } | 275 | } |
598 | 276 | ||
599 | void client::follow(const user& toFollow) const | 277 | void client::follow(const user& toFollow) const |
600 | { | 278 | { |
601 | return follow(toFollow.getID()); | 279 | return follow(toFollow.getID()); |
602 | } | 280 | } |
603 | 281 | ||
604 | void client::unfollow(user_id toUnfollow) const | 282 | void client::unfollow(user_id toUnfollow) const |
605 | { | 283 | { |
606 | std::stringstream datastrstream; | 284 | std::stringstream datastrstream; |
607 | datastrstream << "user_id="; | 285 | datastrstream << "user_id="; |
608 | datastrstream << toUnfollow; | 286 | datastrstream << toUnfollow; |
609 | 287 | ||
610 | post(*_oauth_client, "https://api.twitter.com/1.1/friendships/destroy.json", datastrstream.str()).perform(); | 288 | post(auth_, "https://api.twitter.com/1.1/friendships/destroy.json", datastrstream.str()).perform(); |
611 | } | 289 | } |
612 | 290 | ||
613 | void client::unfollow(const user& toUnfollow) const | 291 | void client::unfollow(const user& toUnfollow) const |
614 | { | 292 | { |
615 | return unfollow(toUnfollow.getID()); | 293 | return unfollow(toUnfollow.getID()); |
@@ -617,23 +295,23 @@ namespace twitter { | |||
617 | 295 | ||
618 | const user& client::getUser() const | 296 | const user& client::getUser() const |
619 | { | 297 | { |
620 | return *_current_user; | 298 | return currentUser_; |
621 | } | 299 | } |
622 | 300 | ||
623 | const configuration& client::getConfiguration() const | 301 | const configuration& client::getConfiguration() const |
624 | { | 302 | { |
625 | if (!_configuration || (difftime(time(NULL), _last_configuration_update) > 60*60*24)) | 303 | if (!_configuration || (difftime(time(NULL), _last_configuration_update) > 60*60*24)) |
626 | { | 304 | { |
627 | _configuration = | 305 | _configuration = |
628 | make_unique<configuration>( | 306 | std::make_unique<configuration>( |
629 | get(*_oauth_client, | 307 | get(auth_, |
630 | "https://api.twitter.com/1.1/help/configuration.json") | 308 | "https://api.twitter.com/1.1/help/configuration.json") |
631 | .perform()); | 309 | .perform()); |
632 | 310 | ||
633 | _last_configuration_update = time(NULL); | 311 | _last_configuration_update = time(NULL); |
634 | } | 312 | } |
635 | 313 | ||
636 | return *_configuration; | 314 | return *_configuration; |
637 | } | 315 | } |
638 | 316 | ||
639 | }; | 317 | }; |
diff --git a/src/client.h b/src/client.h index 2230dbb..c0a63eb 100644 --- a/src/client.h +++ b/src/client.h | |||
@@ -10,58 +10,66 @@ | |||
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(); | 21 | |
27 | |||
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; |
30 | 24 | ||
31 | tweet replyToTweet(std::string msg, tweet_id in_response_to, std::list<long> media_ids = {}) const; | 25 | tweet replyToTweet(std::string msg, tweet_id in_response_to, std::list<long> media_ids = {}) const; |
32 | 26 | ||
33 | std::set<user_id> getFriends(user_id id) const; | 27 | std::set<user_id> getFriends(user_id id) const; |
34 | std::set<user_id> getFriends(const user& u) const; | 28 | std::set<user_id> getFriends(const user& u) const; |
35 | std::set<user_id> getFriends() const; | 29 | std::set<user_id> getFriends() const; |
36 | 30 | ||
37 | std::set<user_id> getFollowers(user_id id) const; | 31 | std::set<user_id> getFollowers(user_id id) const; |
38 | std::set<user_id> getFollowers(const user& u) const; | 32 | std::set<user_id> getFollowers(const user& u) const; |
39 | std::set<user_id> getFollowers() const; | 33 | std::set<user_id> getFollowers() const; |
40 | 34 | ||
41 | void follow(user_id toFollow) const; | 35 | void follow(user_id toFollow) const; |
42 | void follow(const user& toFollow) const; | 36 | void follow(const user& toFollow) const; |
43 | 37 | ||
44 | void unfollow(user_id toUnfollow) const; | 38 | void unfollow(user_id toUnfollow) const; |
45 | void unfollow(const user& toUnfollow) const; | 39 | void unfollow(const user& toUnfollow) const; |
46 | 40 | ||
47 | const user& getUser() const; | 41 | const user& getUser() const; |
48 | 42 | ||
49 | const configuration& getConfiguration() const; | 43 | const configuration& getConfiguration() const; |
50 | 44 | ||
45 | timeline& getHomeTimeline() | ||
46 | { | ||
47 | return homeTimeline_; | ||
48 | } | ||
49 | |||
50 | timeline& getMentionsTimeline() | ||
51 | { | ||
52 | return mentionsTimeline_; | ||
53 | } | ||
54 | |||
51 | private: | 55 | private: |
52 | 56 | ||
53 | friend class stream; | 57 | const auth& auth_; |
54 | 58 | ||
55 | std::unique_ptr<OAuth::Consumer> _oauth_consumer; | 59 | user currentUser_; |
56 | std::unique_ptr<OAuth::Token> _oauth_token; | 60 | |
57 | std::unique_ptr<OAuth::Client> _oauth_client; | ||
58 | |||
59 | std::unique_ptr<user> _current_user; | ||
60 | |||
61 | mutable std::unique_ptr<configuration> _configuration; | 61 | mutable std::unique_ptr<configuration> _configuration; |
62 | mutable time_t _last_configuration_update; | 62 | mutable time_t _last_configuration_update; |
63 | |||
64 | timeline homeTimeline_ { | ||
65 | auth_, | ||
66 | "https://api.twitter.com/1.1/statuses/home_timeline.json"}; | ||
67 | |||
68 | timeline mentionsTimeline_ { | ||
69 | auth_, | ||
70 | "https://api.twitter.com/1.1/statuses/mentions_timeline.json"}; | ||
63 | }; | 71 | }; |
64 | 72 | ||
65 | }; | 73 | }; |
66 | 74 | ||
67 | #endif /* end of include guard: TWITTER_H_ABFF6A12 */ | 75 | #endif /* end of include guard: TWITTER_H_ABFF6A12 */ |
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 */ |