Files @ 885741503728
Branch filter:

Location: libtransport.git/backends/twitter/TwitterResponseParser.cpp - annotation

Vitaly Takmazov
add libjsoncpp-dev to dependencies
929b49d6412d
78e71f9345c7
9469109d37e4
bdb8aed78f63
50119c8e4ef2
50119c8e4ef2
ae2c0acb5058
ae2c0acb5058
929b49d6412d
bdb8aed78f63
bdb8aed78f63
bdb8aed78f63
e63427c2da8a
bdb8aed78f63
bdb8aed78f63
bdb8aed78f63
86626d92ff59
86626d92ff59
86626d92ff59
86626d92ff59
86626d92ff59
86626d92ff59
b546e57b5033
9469109d37e4
9469109d37e4
9469109d37e4
9469109d37e4
9469109d37e4
9469109d37e4
b546e57b5033
b546e57b5033
b546e57b5033
b546e57b5033
b546e57b5033
9469109d37e4
9469109d37e4
9469109d37e4
9388d599156c
50119c8e4ef2
50119c8e4ef2
50119c8e4ef2
50119c8e4ef2
50119c8e4ef2
50119c8e4ef2
50119c8e4ef2
50119c8e4ef2
50119c8e4ef2
d93cc2ce66eb
50119c8e4ef2
9388d599156c
9388d599156c
1c07b23da64e
ffd0baea6fd9
ffd0baea6fd9
1c07b23da64e
d93cc2ce66eb
ffd0baea6fd9
ffd0baea6fd9
1c07b23da64e
86626d92ff59
b546e57b5033
1c07b23da64e
1c07b23da64e
86626d92ff59
1c07b23da64e
86626d92ff59
1c07b23da64e
fb8216d261e8
1c07b23da64e
1c07b23da64e
d93cc2ce66eb
ffd0baea6fd9
ffd0baea6fd9
ffd0baea6fd9
d93cc2ce66eb
929b49d6412d
929b49d6412d
1c07b23da64e
d93cc2ce66eb
929b49d6412d
929b49d6412d
929b49d6412d
86626d92ff59
1c07b23da64e
1c07b23da64e
1c07b23da64e
1c07b23da64e
d93cc2ce66eb
1c07b23da64e
929b49d6412d
929b49d6412d
929b49d6412d
d93cc2ce66eb
929b49d6412d
929b49d6412d
b546e57b5033
1c07b23da64e
86626d92ff59
b546e57b5033
1c07b23da64e
1c07b23da64e
86626d92ff59
1c07b23da64e
86626d92ff59
1c07b23da64e
1c07b23da64e
1c07b23da64e
1c07b23da64e
1c07b23da64e
1c07b23da64e
1c07b23da64e
1c07b23da64e
b546e57b5033
b546e57b5033
86626d92ff59
1c07b23da64e
1c07b23da64e
d7f234fb19cb
d93cc2ce66eb
929b49d6412d
929b49d6412d
929b49d6412d
d93cc2ce66eb
11937227ff60
11937227ff60
d93cc2ce66eb
1c07b23da64e
86626d92ff59
b546e57b5033
86626d92ff59
86626d92ff59
1c07b23da64e
1c07b23da64e
1c07b23da64e
1c07b23da64e
11937227ff60
11937227ff60
11937227ff60
1c07b23da64e
929b49d6412d
929b49d6412d
1c07b23da64e
d93cc2ce66eb
1c07b23da64e
d93cc2ce66eb
d93cc2ce66eb
b297329ba32f
b297329ba32f
b297329ba32f
1c07b23da64e
d93cc2ce66eb
d93cc2ce66eb
929b49d6412d
929b49d6412d
929b49d6412d
1c07b23da64e
1c07b23da64e
929b49d6412d
929b49d6412d
929b49d6412d
26e5289cefeb
1c07b23da64e
11937227ff60
11937227ff60
1c07b23da64e
d93cc2ce66eb
d93cc2ce66eb
1c07b23da64e
d93cc2ce66eb
d93cc2ce66eb
11937227ff60
11937227ff60
11937227ff60
1c07b23da64e
d93cc2ce66eb
d93cc2ce66eb
1c07b23da64e
1c07b23da64e
11937227ff60
1c07b23da64e
1c07b23da64e
11937227ff60
11937227ff60
11937227ff60
11937227ff60
1c07b23da64e
9111a3993741
9111a3993741
1c07b23da64e
d93cc2ce66eb
d93cc2ce66eb
1c07b23da64e
d93cc2ce66eb
d93cc2ce66eb
b297329ba32f
b297329ba32f
b297329ba32f
1c07b23da64e
d93cc2ce66eb
d93cc2ce66eb
9111a3993741
9111a3993741
9111a3993741
1c07b23da64e
1c07b23da64e
9111a3993741
d93cc2ce66eb
9111a3993741
9111a3993741
1c07b23da64e
bdb8aed78f63
bdb8aed78f63
1c07b23da64e
d93cc2ce66eb
1c07b23da64e
d93cc2ce66eb
d93cc2ce66eb
bdb8aed78f63
bdb8aed78f63
bdb8aed78f63
1c07b23da64e
d93cc2ce66eb
d93cc2ce66eb
bdb8aed78f63
bdb8aed78f63
bdb8aed78f63
1c07b23da64e
bdb8aed78f63
bdb8aed78f63
1c07b23da64e
26e5289cefeb
26e5289cefeb
1c07b23da64e
d93cc2ce66eb
1c07b23da64e
d93cc2ce66eb
d93cc2ce66eb
b297329ba32f
b297329ba32f
b297329ba32f
1c07b23da64e
1c07b23da64e
d93cc2ce66eb
26e5289cefeb
26e5289cefeb
26e5289cefeb
1c07b23da64e
d93cc2ce66eb
e63427c2da8a
86626d92ff59
26e5289cefeb
26e5289cefeb
26e5289cefeb
e9891aa2000a
1c07b23da64e
e9891aa2000a
c236c464ffac
7e9dfbdeadda
c236c464ffac
1c07b23da64e
d93cc2ce66eb
1c07b23da64e
d93cc2ce66eb
d93cc2ce66eb
c236c464ffac
b297329ba32f
f0285e059882
d93cc2ce66eb
f0285e059882
f0285e059882
86626d92ff59
f0285e059882
f0285e059882
f0285e059882
c236c464ffac
c236c464ffac
c236c464ffac
e9891aa2000a
b546e57b5033
d93cc2ce66eb
b546e57b5033
b546e57b5033
b546e57b5033
b546e57b5033
b546e57b5033
d93cc2ce66eb
b546e57b5033
b546e57b5033
d93cc2ce66eb
b546e57b5033
d93cc2ce66eb
b546e57b5033
b546e57b5033
b546e57b5033
b546e57b5033
d93cc2ce66eb
b546e57b5033
b546e57b5033
#include "TwitterResponseParser.h"
#include "transport/Logging.h"
#include "boost/algorithm/string.hpp"
#include <cctype>
#include "boost/date_time/local_time/local_time.hpp"
#include "boost/date_time/time_facet.hpp"

DEFINE_LOGGER(logger, "TwitterResponseParser")

static std::string tolowercase(std::string inp)
{
	std::string out = inp;
	for(unsigned i=0 ; i<out.size() ; i++) out[i] = tolower(out[i]);
	return out;
}

template <class T> std::string stringOf(T object) {
	std::ostringstream os;
	os << object;
	return (os.str());
}

static std::string unescape(std::string data, std::vector<UrlEntity> urls) {
	using boost::algorithm::replace_all;
	replace_all(data, "&amp;",  "&");
	replace_all(data, "&quot;", "\"");
	replace_all(data, "&apos;", "\'");
	replace_all(data, "&lt;",   "<");
	replace_all(data, "&gt;",   ">");

	for (std::vector<UrlEntity>::size_type i = 0; i < urls.size(); i++) {
		replace_all(data, urls[i].getUrl(), urls[i].getExpandedUrl());
	}

	return data;
}

static std::string toIsoTime(std::string in) {
	std::locale locale(std::locale::classic(), new boost::local_time::local_time_input_facet("%a %b %d %H:%M:%S +0000 %Y"));
	boost::local_time::local_time_facet* output_facet = new boost::local_time::local_time_facet();
	boost::local_time::local_date_time ldt(boost::local_time::not_a_date_time);
	std::stringstream ss(in);
	ss.imbue(locale);
	ss.imbue(std::locale(ss.getloc(), output_facet));
	output_facet->format("%Y%m%dT%H%M%S"); // boost::local_time::local_time_facet::iso_time_format_specifier ?
	ss >> ldt;
	ss.str("");
	ss << ldt;
	return ss.str();
}

EmbeddedStatus getEmbeddedStatus(const rapidjson::Value &element)
{
	EmbeddedStatus status;
	if(!element.IsObject()) {
		LOG4CXX_ERROR(logger, "Not a status element!");
		return status;
	}
	status.setCreationTime( toIsoTime ( std::string( element[TwitterReponseTypes::created_at.c_str()].GetString() ) ) );
	status.setID( stringOf( element[TwitterReponseTypes::id.c_str()].GetInt64() ) );
	status.setTweet( unescape ( std::string( element[TwitterReponseTypes::text.c_str()].GetString() ), getUrlEntities(element) ) );
	status.setTruncated( element[TwitterReponseTypes::truncated.c_str()].GetBool());
	status.setReplyToStatusID( element[TwitterReponseTypes::in_reply_to_status_id.c_str()].IsNull() ?
"" : stringOf(element[TwitterReponseTypes::in_reply_to_status_id.c_str()].GetInt64()) );
	status.setReplyToUserID( element[TwitterReponseTypes::in_reply_to_user_id.c_str()].IsNull() ?
"" : stringOf(element[TwitterReponseTypes::in_reply_to_user_id.c_str()].GetInt64())  );
	status.setReplyToScreenName( element[TwitterReponseTypes::in_reply_to_screen_name.c_str()].IsNull() ?
"" : std::string(element[TwitterReponseTypes::in_reply_to_screen_name.c_str()].GetString()) );
	status.setRetweetCount( element[TwitterReponseTypes::retweet_count.c_str()].GetInt64() );
	status.setFavorited( element[TwitterReponseTypes::favorited.c_str()].GetBool() );
	status.setRetweeted( element[TwitterReponseTypes::retweeted.c_str()].GetBool());
	return status;
}

User getUser(const rapidjson::Value &element)
{
	User user;
	if(!element.IsObject()) {
		LOG4CXX_ERROR(logger, "Not a user element!");
		return user;
	}

	user.setUserID( stringOf( element[TwitterReponseTypes::id.c_str()].GetInt64() ) );
	user.setScreenName( tolowercase( std::string( element[TwitterReponseTypes::screen_name.c_str()].GetString() ) ) );
	user.setUserName( std::string( element[TwitterReponseTypes::name.c_str()].GetString() ) );
	user.setProfileImgURL( std::string( element[TwitterReponseTypes::profile_image_url.c_str()].GetString() ) );
	user.setNumberOfTweets( element[TwitterReponseTypes::statuses_count.c_str()].GetInt64() );
	if(element[TwitterReponseTypes::status.c_str()].IsObject())
		user.setLastStatus(getEmbeddedStatus(element[TwitterReponseTypes::status.c_str()]));
	return user;
}

Status getStatus(const rapidjson::Value &element)
{
	Status status;

	status.setCreationTime( toIsoTime ( std::string( element[TwitterReponseTypes::created_at.c_str()].GetString() ) ) );
	status.setID( stringOf( element[TwitterReponseTypes::id.c_str()].GetInt64()  ));
	status.setTweet( unescape ( std::string( element[TwitterReponseTypes::text.c_str()].GetString() ), getUrlEntities(element) ) );
	status.setTruncated( element[TwitterReponseTypes::truncated.c_str()].GetBool());
	status.setReplyToStatusID( element[TwitterReponseTypes::in_reply_to_status_id.c_str()].IsNull() ?
"" : stringOf(element[TwitterReponseTypes::in_reply_to_status_id.c_str()].GetInt64()) );
	status.setReplyToUserID( element[TwitterReponseTypes::in_reply_to_user_id.c_str()].IsNull() ?
"" : stringOf(element[TwitterReponseTypes::in_reply_to_user_id.c_str()].GetInt64())  );
	status.setReplyToScreenName( element[TwitterReponseTypes::in_reply_to_screen_name.c_str()].IsNull() ?
"" : std::string(element[TwitterReponseTypes::in_reply_to_screen_name.c_str()].GetString()) );
	status.setUserData( getUser(element[TwitterReponseTypes::user.c_str()]) );
	status.setRetweetCount( element[TwitterReponseTypes::retweet_count.c_str()].GetInt64() );
	status.setFavorited( element[TwitterReponseTypes::favorited.c_str()].GetBool() );
	status.setRetweeted( element[TwitterReponseTypes::retweeted.c_str()].GetBool());
	const rapidjson::Value &rt = element[TwitterReponseTypes::retweeted_status.c_str()];
	if (rt.IsObject()) {
		status.setTweet(unescape( std::string( rt[TwitterReponseTypes::text.c_str()].GetString()) + " (RT by @" + status.getUserData().getScreenName() + ")"
			, getUrlEntities(element)) );
		status.setRetweetID( stringOf(rt[TwitterReponseTypes::id.c_str()].GetInt64()) );
		status.setCreationTime( toIsoTime ( std::string (rt[TwitterReponseTypes::created_at.c_str()].GetString() ) ) );
		status.setUserData( getUser ( rt[TwitterReponseTypes::user.c_str()]) );
	}

	return status;
}

DirectMessage getDirectMessage(const rapidjson::Value &element)
{
	DirectMessage DM;

	DM.setCreationTime( toIsoTime ( std::string( element[TwitterReponseTypes::created_at.c_str()].GetString() ) ) );
	DM.setID( stringOf( element[TwitterReponseTypes::id.c_str()].GetInt64() ) );
	DM.setMessage( unescape ( std::string( element[TwitterReponseTypes::text.c_str()].GetString() ), getUrlEntities(element) ) );
	DM.setSenderID( stringOf( element[TwitterReponseTypes::sender_id.c_str()].GetInt64())  );
	DM.setRecipientID( stringOf( element[TwitterReponseTypes::recipient_id.c_str()].GetInt64() ) );
	DM.setSenderScreenName( std::string( element[TwitterReponseTypes::sender_screen_name.c_str()].GetString() ) );
	DM.setRecipientScreenName( std::string( element[TwitterReponseTypes::recipient_screen_name.c_str()].GetString() ) );
	DM.setSenderData( getUser(element[TwitterReponseTypes::sender.c_str()] ));
	DM.setRecipientData( getUser(element[TwitterReponseTypes::recipient.c_str()]) );
	return DM;
}

std::vector<Status> getTimeline(std::string &json)
{
	std::vector<Status> statuses;
	rapidjson::Document rootElement;

	if(rootElement.Parse<0>(json.c_str()).HasParseError()) {
		LOG4CXX_ERROR(logger, "Error while parsing JSON");
		LOG4CXX_ERROR(logger, json);
		return statuses;
	}

	if(!rootElement.IsArray()) {
		LOG4CXX_ERROR(logger, "JSON doesn't correspond to timeline:");
		LOG4CXX_ERROR(logger, json);
		return statuses;
	}

	for(rapidjson::SizeType i = 0; i < rootElement.Size(); i++) {
		statuses.push_back(getStatus(rootElement[i]));
	}
	return statuses;
}

std::vector<DirectMessage> getDirectMessages(std::string &json)
{
	std::vector<DirectMessage> DMs;
	rapidjson::Document rootElement;


	if(rootElement.Parse<0>(json.c_str()).HasParseError()) {
		LOG4CXX_ERROR(logger, "Error while parsing JSON");
		LOG4CXX_ERROR(logger, json);
		return DMs;
	}

	if(!rootElement.IsArray()) {
		LOG4CXX_ERROR(logger, "JSON doesn't correspond to direct messages:");
		LOG4CXX_ERROR(logger, json);
		return DMs;
	}

	for(rapidjson::SizeType i = 0; i < rootElement.Size(); i++) {
		DMs.push_back(getDirectMessage(rootElement[i]));
	}
	return DMs;
}

std::vector<User> getUsers(std::string &json)
{
	std::vector<User> users;
	rapidjson::Document rootElement;


	if(rootElement.Parse<0>(json.c_str()).HasParseError()) {
		LOG4CXX_ERROR(logger, "Error while parsing JSON");
		LOG4CXX_ERROR(logger, json);
		return users;
	}

	if(!rootElement.IsArray()) {
		LOG4CXX_ERROR(logger, "JSON doesn't correspond to user list:");
		LOG4CXX_ERROR(logger, json);
		return users;
	}

	for(rapidjson::SizeType i = 0; i < rootElement.Size(); i++) {
		users.push_back(getUser(rootElement[i]));
	}
	return users;
}

User getUser(std::string &json)
{
	User user;
	rapidjson::Document rootElement;

	if(rootElement.Parse<0>(json.c_str()).HasParseError()) {
		LOG4CXX_ERROR(logger, "Error while parsing JSON");
		LOG4CXX_ERROR(logger, json);
		return user;
	}

	if(!rootElement.IsObject()) {
		LOG4CXX_ERROR(logger, "JSON doesn't correspond to user object");
		LOG4CXX_ERROR(logger, json);
		return user;
	}

	return user = getUser(rootElement);
}

std::vector<std::string> getIDs(std::string &json)
{
	std::vector<std::string> IDs;
	rapidjson::Document rootElement;

	if(rootElement.Parse<0>(json.c_str()).HasParseError()) {
		LOG4CXX_ERROR(logger, "Error while parsing JSON");
		LOG4CXX_ERROR(logger, json);
		return IDs;
	}

	if(!rootElement.IsObject()) {
		LOG4CXX_ERROR(logger, "JSON doesn't correspond to id_list");
		LOG4CXX_ERROR(logger, json);
		return IDs;
	}

	const rapidjson::Value & ids = rootElement[TwitterReponseTypes::ids.c_str()];

	for(unsigned i=0 ; i<ids.Size() ; i++) {
		IDs.push_back(stringOf( ids[i].GetInt64()) );
	}
	return IDs;
}

Error getErrorMessage(std::string &json)
{
	std::string error = "";
	std::string code = "0";
	Error resp;
	rapidjson::Document rootElement;

	if(rootElement.Parse<0>(json.c_str()).HasParseError()) {
		LOG4CXX_ERROR(logger, "Error while parsing JSON");
		LOG4CXX_ERROR(logger, json);
		return resp;
	}
	if (rootElement.IsObject()) {
		if (!rootElement["errors"].IsNull()) {
			const rapidjson::Value &errorElement = rootElement["errors"][0u]; // first error
			error = std::string(errorElement["message"].GetString());
			code = stringOf(errorElement["code"].GetInt64());
			resp.setCode(code);
			resp.setMessage(error);
		}
	}

	return resp;
}

std::vector<UrlEntity> getUrlEntities(const rapidjson::Value &element)
{

	std::vector<UrlEntity> url_entities;

	const rapidjson::Value &entities = element["entities"];

	if (entities.IsObject()) {
		const rapidjson::Value &urls = entities["urls"];
		if (urls.IsArray()) {
			for (rapidjson::SizeType i = 0; i < urls.Size(); i++) {
				UrlEntity entity(urls[i]["url"].GetString(), urls[i]["expanded_url"].GetString());
				url_entities.push_back(entity);
			}
		}
	}

	return url_entities;
}