Skip to content

Instantly share code, notes, and snippets.

@roxlu
Created January 5, 2012 13:19
Show Gist options
  • Select an option

  • Save roxlu/1565222 to your computer and use it in GitHub Desktop.

Select an option

Save roxlu/1565222 to your computer and use it in GitHub Desktop.
#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