Created
January 5, 2012 13:19
-
-
Save roxlu/1565222 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "TwitterStream.h" | |
| #include <sstream> | |
| #include <iostream> | |
| #define CHECK_CURL_ERROR(result) if((result) != CURLE_OK) { printf("Curl error: %s.\n", curl_easy_strerror((result))); return false; } | |
| #define CHECK_CURLM_ERROR(result) if((result) != CURLM_OK) { printf("Curl multi error: %s.\n", curl_multi_strerror((result))); return false; } | |
| using std::stringstream; | |
| namespace roxlu { | |
| TwitterStream::TwitterStream() | |
| :connected(false) | |
| ,parsed_http_headers(false) | |
| { | |
| } | |
| bool TwitterStream::connect(string username, string password, const vector<string>& tags) { | |
| CURLcode r; | |
| // create curl handle. | |
| curl = curl_easy_init(); | |
| if(!curl) { | |
| curl_easy_cleanup(curl); | |
| printf("Error: cannot create easy handle.\n"); | |
| return false; | |
| } | |
| // create the url | |
| stringstream ss; | |
| ss << "https://stream.twitter.com/1/statuses/filter.json?track="; | |
| for(int i = 0; i < tags.size(); ++i) { | |
| ss << tags[i]; | |
| if(i < tags.size()-1) { | |
| ss << ","; | |
| } | |
| } | |
| printf(">> %s\n", ss.str().c_str()); | |
| r = curl_easy_setopt(curl, CURLOPT_URL, ss.str().c_str()); | |
| CHECK_CURL_ERROR(r); | |
| // set login | |
| stringstream userpass; | |
| userpass << username << ":" << password; | |
| r = curl_easy_setopt(curl, CURLOPT_USERPWD, userpass.str().c_str()); | |
| CHECK_CURL_ERROR(r); | |
| // no CA verification. | |
| r = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE); | |
| CHECK_CURL_ERROR(r); | |
| // called when data is received (unencrypted) | |
| r = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &TwitterStream::writeData); | |
| CHECK_CURL_ERROR(r); | |
| // object we get passed into writeData | |
| r = curl_easy_setopt(curl, CURLOPT_WRITEDATA, this); | |
| CHECK_CURL_ERROR(r); | |
| //curl_easy_setopt(curl, CURLOPT_VERBOSE, true); | |
| // create multi handle for async io | |
| curlm = curl_multi_init(); | |
| if(curlm == NULL) { | |
| printf("Cannot initialize curl multi.\n"); | |
| return false; | |
| } | |
| // add the easy handle to the multi stack. | |
| CURLMcode t = curl_multi_add_handle(curlm, curl); | |
| CHECK_CURLM_ERROR(t); | |
| connected = true; | |
| return true; | |
| } | |
| bool TwitterStream::disconnect() { | |
| if(connected) { | |
| parsed_http_headers = false; | |
| connected = false; | |
| CURLMcode r = curl_multi_remove_handle(curlm, curl); | |
| CHECK_CURLM_ERROR(r); | |
| curl_easy_cleanup(curl); | |
| r = curl_multi_cleanup(curlm); | |
| CHECK_CURLM_ERROR(r); | |
| } | |
| return true; | |
| } | |
| bool TwitterStream::update() { | |
| if(!connected) { | |
| return false; | |
| } | |
| int still_running = 0; | |
| CURLMcode r = curl_multi_perform(curlm, &still_running); | |
| CHECK_CURLM_ERROR(r); | |
| if(still_running == 0) { | |
| printf("not running...\n"); | |
| } | |
| else { | |
| } | |
| return true; | |
| } | |
| void TwitterStream::parseBuffer() { | |
| // check for the http response headers | |
| // if(!parsed_http_headers) { | |
| // int len = buffer.size(); | |
| // for(int i = 0; i < len-4; ++i) { | |
| // printf("Check: %c\n", buffer[i]); | |
| // if(buffer[i] == '\r' && buffer[i+1] == '\n' && buffer[i+2] == '\r' && buffer[i+3] == '\n') { | |
| // parsed_http_headers = true; | |
| // buffer.erase(0, i); // remove from buffer | |
| // break; | |
| // } | |
| // } | |
| // return; | |
| // } | |
| // after we received the http response | |
| stringstream ss(buffer); | |
| string line; | |
| int num_chars = 0; | |
| while(std::getline(ss, line, '\r')) { | |
| int n = line.size(); | |
| if(n == 1) { | |
| num_chars += 1; | |
| continue; | |
| } | |
| num_chars += n + 1; | |
| line = TwitterStream::trim(line); | |
| parseTweetJSON(line); | |
| } | |
| if(num_chars > 0) { | |
| buffer.erase(0, num_chars); | |
| } | |
| } | |
| void TwitterStream::parseTweetJSON(string& json) { | |
| json_t* root; | |
| json_error_t error; | |
| Tweet tweet; | |
| root = json_loads(json.c_str(), 0, &error); | |
| if(!root) { | |
| printf("Error: on line: %d, %s\n", error.line, error.text); | |
| //printf("Line: -%s-\n----\n", json.c_str()); | |
| return; | |
| } | |
| // text | |
| json_t* node = json_object_get(root, "text"); | |
| if(!json_is_string(node)) { | |
| printf("Error: cannot get text from tweet.\n"); | |
| return; | |
| } | |
| string text = json_string_value(node); | |
| tweet.setText(text); | |
| printf(">> '''%s'''\n", text.c_str()); | |
| /* | |
| // load json. | |
| root = json_loads(sJSON.c_str(), 0, &error); | |
| if(!root) { | |
| cout << "error: on line:" << error.line << ", " << error.text << endl; | |
| return; | |
| } | |
| // text | |
| json_t* node = json_object_get(root, "text"); | |
| if(!json_is_string(node)) { | |
| cout << "error: cannot get text from tweet" << endl; | |
| return; | |
| } | |
| string text = json_string_value(node); | |
| tweet.setText(text); | |
| // id_str | |
| node = json_object_get(root, "id_str"); | |
| if(!json_is_string(node)) { | |
| cout << "error: cannot get id_str from tweet" << endl; | |
| return; | |
| } | |
| string id = json_string_value(node); | |
| tweet.setID(id); | |
| // user - object | |
| json_t* user = json_object_get(root, "user"); | |
| if(!json_is_object(user)) { | |
| cout << "error: cannot get user node from tweet" << endl; | |
| return; | |
| } | |
| // user: screen name | |
| node = json_object_get(user, "screen_name"); | |
| if(!json_is_string(node)) { | |
| cout << "error: cannot get user screen_name" << endl; | |
| return; | |
| } | |
| string screen_name = json_string_value(node); | |
| tweet.setScreenName(screen_name); | |
| // user: avatar | |
| node = json_object_get(user, "profile_image_url"); | |
| if(!json_is_string(node)) { | |
| cout << "error: cannot get profile_image_url" << endl; | |
| return; | |
| } | |
| string profile_image = json_string_value(node); | |
| tweet.setAvatar(profile_image); | |
| // user: id | |
| node = json_object_get(user, "id_str"); | |
| if(!json_is_string(node)) { | |
| cout << "error: cannot get user id" << endl; | |
| return; | |
| } | |
| string user_id = json_string_value(node); | |
| tweet.setUserID(user_id); | |
| // store tweet. | |
| lock.writeLock(); | |
| tweets.push_back(tweet); | |
| lock.unlock(); | |
| */ | |
| } | |
| size_t TwitterStream::writeData(void *ptr, size_t s, size_t nmemb, void* obj) { | |
| TwitterStream* stream = static_cast<TwitterStream*>(obj); | |
| size_t bytes_to_write = s * nmemb; | |
| char* data_ptr = static_cast<char*>(ptr); | |
| // for(int i = 0; i < bytes_to_write; ++i) { | |
| // printf("%c", data_ptr[i]); | |
| // } | |
| stream->buffer.append(data_ptr, bytes_to_write); | |
| stream->parseBuffer(); | |
| return bytes_to_write; | |
| } | |
| }; // roxlu |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment