1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-12 00:54:20 +02:00

Sync with upstream qtweetlib

This commit is contained in:
Jeff Mitchell
2011-03-22 10:12:46 -04:00
parent 2ffe51163c
commit c15c99cfa9
5 changed files with 123 additions and 80 deletions

View File

@@ -61,6 +61,7 @@ QTweetStatus QTweetConvert::variantMapToStatus(const QVariantMap &var)
status.setId(var["id"].toLongLong()); status.setId(var["id"].toLongLong());
status.setInReplyToUserId(var["in_reply_to_user_id"].toLongLong()); status.setInReplyToUserId(var["in_reply_to_user_id"].toLongLong());
status.setInReplyToScreenName(var["in_reply_to_screen_name"].toString()); status.setInReplyToScreenName(var["in_reply_to_screen_name"].toString());
status.setFavorited(var["favorited"].toBool());
QVariantMap userMap = var["user"].toMap(); QVariantMap userMap = var["user"].toMap();
QTweetUser user = variantMapToUserInfo(userMap); QTweetUser user = variantMapToUserInfo(userMap);

View File

@@ -64,7 +64,7 @@ void QTweetFriendshipDestroy::unfollow(qint64 userid, bool includeEntities)
QNetworkRequest req(url); QNetworkRequest req(url);
QByteArray oauthHeader = oauthTwitter()->generateAuthorizationHeader(url, OAuth::GET); QByteArray oauthHeader = oauthTwitter()->generateAuthorizationHeader(url, OAuth::DELETE);
req.setRawHeader(AUTH_HEADER, oauthHeader); req.setRawHeader(AUTH_HEADER, oauthHeader);
QNetworkReply *reply = oauthTwitter()->networkAccessManager()->deleteResource(req); QNetworkReply *reply = oauthTwitter()->networkAccessManager()->deleteResource(req);
@@ -92,7 +92,7 @@ void QTweetFriendshipDestroy::unfollow(const QString &screenName, bool includeEn
QNetworkRequest req(url); QNetworkRequest req(url);
QByteArray oauthHeader = oauthTwitter()->generateAuthorizationHeader(url, OAuth::GET); QByteArray oauthHeader = oauthTwitter()->generateAuthorizationHeader(url, OAuth::DELETE);
req.setRawHeader(AUTH_HEADER, oauthHeader); req.setRawHeader(AUTH_HEADER, oauthHeader);
QNetworkReply *reply = oauthTwitter()->networkAccessManager()->deleteResource(req); QNetworkReply *reply = oauthTwitter()->networkAccessManager()->deleteResource(req);

View File

@@ -69,7 +69,7 @@ void QTweetSearchResult::setCreatedAt(const QDateTime &dateTime)
void QTweetSearchResult::setCreatedAt(const QString &twitterDate) void QTweetSearchResult::setCreatedAt(const QString &twitterDate)
{ {
QString dateString = twitterDate.left(3) + ' ' + twitterDate.mid(8, 3) + ' ' + QString dateString = twitterDate.left(3) + ' ' + twitterDate.mid(8, 3) + ' ' +
twitterDate.mid(5, 2) + ' ' + twitterDate.mid(13, 4); twitterDate.mid(5, 2) + ' ' + twitterDate.mid(12, 4);
QString timeString = twitterDate.mid(17, 8); QString timeString = twitterDate.mid(17, 8);
QDate date = QDate::fromString(dateString); QDate date = QDate::fromString(dateString);

View File

@@ -33,14 +33,28 @@
#define TWITTER_USERSTREAM_URL "https://userstream.twitter.com/2/user.json" #define TWITTER_USERSTREAM_URL "https://userstream.twitter.com/2/user.json"
// ### TODO User Agent or X-User-Agent
/** /**
* Constructor * Constructor
*/ */
QTweetUserStream::QTweetUserStream(QObject *parent) : QTweetUserStream::QTweetUserStream(QObject *parent) :
QObject(parent), m_oauthTwitter(0), m_reply(0), m_backofftimer(new QTimer(this)) QObject(parent), m_oauthTwitter(0), m_reply(0),
m_backofftimer(new QTimer(this)),
m_timeoutTimer(new QTimer(this)),
m_streamTryingReconnect(false)
{ {
m_backofftimer->setInterval(20000);
m_backofftimer->setSingleShot(true); m_backofftimer->setSingleShot(true);
connect(m_backofftimer, SIGNAL(timeout()), this, SLOT(startFetching())); connect(m_backofftimer, SIGNAL(timeout()), this, SLOT(startFetching()));
m_timeoutTimer->setInterval(90000);
connect(m_timeoutTimer, SIGNAL(timeout()), this, SLOT(replyTimeout()));
#ifdef STREAM_LOGGER
m_streamLog.setFileName("streamlog.txt");
m_streamLog.open(QIODevice::WriteOnly | QIODevice::Text);
#endif
} }
/** /**
@@ -59,49 +73,6 @@ OAuthTwitter* QTweetUserStream::oauthTwitter() const
return m_oauthTwitter; return m_oauthTwitter;
} }
/**
* Called when there is network error
*/
void QTweetUserStream::replyError(QNetworkReply::NetworkError code)
{
qDebug() << "Reply error: " << code;
// ### TODO: determine network error codes, assumptions here
if (code < 200) {
//linear backoff
if (m_backofftimer->interval() < 250) {
m_backofftimer->setInterval(250);
} else {
int nextLinInterval = m_backofftimer->interval() + 250;
if (nextLinInterval > 16000) //cap
nextLinInterval = 16000;
m_backofftimer->setInterval(nextLinInterval);
}
m_backofftimer->start();
return;
}
if (code > 200) {
//exp. backoff
if (m_backofftimer->interval() < 10000) {
m_backofftimer->setInterval(10000);
} else {
int nextExpInterval = 2 * m_backofftimer->interval();
if (nextExpInterval > 240000)
nextExpInterval = 240000;
m_backofftimer->setInterval(240000);
}
m_backofftimer->start();
}
}
/** /**
* Starts fetching user stream * Starts fetching user stream
*/ */
@@ -122,7 +93,9 @@ void QTweetUserStream::startFetching()
m_reply = m_oauthTwitter->networkAccessManager()->get(req); m_reply = m_oauthTwitter->networkAccessManager()->get(req);
connect(m_reply, SIGNAL(finished()), this, SLOT(replyFinished())); connect(m_reply, SIGNAL(finished()), this, SLOT(replyFinished()));
connect(m_reply, SIGNAL(readyRead()), this, SLOT(replyReadyRead())); connect(m_reply, SIGNAL(readyRead()), this, SLOT(replyReadyRead()));
connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(replyError(QNetworkReply::NetworkError)));
connect(m_reply, SIGNAL(readyRead()), m_timeoutTimer, SLOT(start()));
connect(m_reply, SIGNAL(finished()), m_timeoutTimer, SLOT(stop()));
} }
/** /**
@@ -130,16 +103,40 @@ void QTweetUserStream::startFetching()
*/ */
void QTweetUserStream::replyFinished() void QTweetUserStream::replyFinished()
{ {
if (!m_reply->error()) { //no error, reconnect qDebug() << "User stream closed ";
//sligh delay for reconnect m_streamTryingReconnect = true;
m_backofftimer->setInterval(250);
if (!m_reply->error()) { //no error, reconnect
qDebug() << "No error, reconnect";
m_reply->deleteLater();
m_reply = 0;
startFetching();
} else { //error
qDebug() << "Error: " << m_reply->error() << ", " << m_reply->errorString();
m_reply->deleteLater();
m_reply = 0;
//if (m_backofftimer->interval() < 20001) {
// m_backofftimer->start();
// return;
//}
//increase back off interval
int nextInterval = 2 * m_backofftimer->interval();
if (nextInterval > 300000) {
m_backofftimer->setInterval(300000);
emit failureConnect();
}
m_backofftimer->setInterval(nextInterval);
m_backofftimer->start(); m_backofftimer->start();
m_reply->deleteLater();
m_reply = 0; qDebug() << "Exp backoff interval: " << nextInterval;
} else { //error, delete QNetworkReply
m_reply->deleteLater();
m_reply = 0;
} }
} }
@@ -147,30 +144,53 @@ void QTweetUserStream::replyReadyRead()
{ {
QByteArray response = m_reply->readAll(); QByteArray response = m_reply->readAll();
//reset timer #ifdef STREAM_LOGGER
m_backofftimer->setInterval(0); m_streamLog.write(response);
m_streamLog.write("\n");
#endif
//split to response to delimited and not delimited part if (m_streamTryingReconnect) {
int lastCarrReturn = response.lastIndexOf('\r'); emit reconnected();
QByteArray rightNotDelimitedPart = response.mid(lastCarrReturn + 1); m_streamTryingReconnect = false;
QByteArray leftDelimitedPart = response.left(lastCarrReturn);
//prepend to left previous not delimited response
leftDelimitedPart = leftDelimitedPart.prepend(m_cashedResponse);
QList<QByteArray> elements = leftDelimitedPart.split('\r');
for (int i = 0; i < elements.size(); ++i) {
if (elements.at(i) != QByteArray(1, '\n')) {
emit stream(elements.at(i));
parseStream(elements.at(i));
}
} }
if (rightNotDelimitedPart != QByteArray(1, '\n')) //set backoff timer to initial interval
m_cashedResponse = rightNotDelimitedPart; m_backofftimer->setInterval(20000);
else
m_cashedResponse.clear(); QByteArray responseWithPreviousCache = response.prepend(m_cachedResponse);
int start = 0;
int end;
while ((end = responseWithPreviousCache.indexOf('\r', start)) != -1) {
if (start != end) {
QByteArray element = responseWithPreviousCache.mid(start, end - start);
if (!element.isEmpty()) {
emit stream(element);
parseStream(element);
}
}
int skip = (response.at(end + 1) == QLatin1Char('\n')) ? 2 : 1;
start = end + skip;
}
//undelimited part just cache it
m_cachedResponse.clear();
if (start != responseWithPreviousCache.size()) {
QByteArray element = responseWithPreviousCache.mid(start);
if (!element.isEmpty())
m_cachedResponse = element;
}
}
void QTweetUserStream::replyTimeout()
{
qDebug() << "Timeout connection";
m_reply->abort();
} }
void QTweetUserStream::parseStream(const QByteArray& data) void QTweetUserStream::parseStream(const QByteArray& data)
@@ -187,6 +207,9 @@ void QTweetUserStream::parsingFinished(const QVariant &json, bool ok, const QStr
{ {
if (!ok) { if (!ok) {
qDebug() << "JSON parsing error: " << errorMsg; qDebug() << "JSON parsing error: " << errorMsg;
#ifdef STREAM_LOGGER
m_streamLog.write("***** JSON parsing error *****\n");
#endif
return; return;
} }

View File

@@ -25,6 +25,10 @@
#include <QNetworkReply> #include <QNetworkReply>
#include "qtweetlib_global.h" #include "qtweetlib_global.h"
#ifdef STREAM_LOGGER
#include <QFile>
#endif
class QNetworkAccessManager; class QNetworkAccessManager;
class QNetworkReply; class QNetworkReply;
class OAuthTwitter; class OAuthTwitter;
@@ -49,7 +53,6 @@ signals:
* Emits stream elements * Emits stream elements
*/ */
void stream(const QByteArray& ); void stream(const QByteArray& );
/** /**
* Emits tweets (parsed) elements from stream * Emits tweets (parsed) elements from stream
*/ */
@@ -68,14 +71,24 @@ signals:
* Emits deletion of status in the stream * Emits deletion of status in the stream
*/ */
void deleteStatusStream(qint64 id, qint64 userid); void deleteStatusStream(qint64 id, qint64 userid);
/**
* Emited when user stream is reconnected after failure
* Usefull when user stream connection fails to fetch missed tweets with REST API
*/
void reconnected();
/**
* Emited when user stream doesn't connect and backoff timer reaches maximum value (300 seconds)
* Usefull when users stream fails to revert to REST API
*/
void failureConnect();
public slots: public slots:
void startFetching(); void startFetching();
private slots: private slots:
void replyError(QNetworkReply::NetworkError code);
void replyFinished(); void replyFinished();
void replyReadyRead(); void replyReadyRead();
void replyTimeout();
void parsingFinished(const QVariant& json, bool ok, const QString& errorMsg); void parsingFinished(const QVariant& json, bool ok, const QString& errorMsg);
private: private:
@@ -84,10 +97,16 @@ private:
void parseDirectMessage(const QVariantMap& streamObject); void parseDirectMessage(const QVariantMap& streamObject);
void parseDeleteStatus(const QVariantMap& streamObject); void parseDeleteStatus(const QVariantMap& streamObject);
QByteArray m_cachedResponse;
OAuthTwitter *m_oauthTwitter; OAuthTwitter *m_oauthTwitter;
QNetworkReply *m_reply; QNetworkReply *m_reply;
QTimer *m_backofftimer; QTimer *m_backofftimer;
QByteArray m_cashedResponse; QTimer *m_timeoutTimer;
bool m_streamTryingReconnect;
#ifdef STREAM_LOGGER
QFile m_streamLog;
#endif
}; };
#endif // QTWEETUSERSTREAM_H #endif // QTWEETUSERSTREAM_H