mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-11 16:44:05 +02:00
Sync with upstream qtweetlib
This commit is contained in:
@@ -61,6 +61,7 @@ QTweetStatus QTweetConvert::variantMapToStatus(const QVariantMap &var)
|
||||
status.setId(var["id"].toLongLong());
|
||||
status.setInReplyToUserId(var["in_reply_to_user_id"].toLongLong());
|
||||
status.setInReplyToScreenName(var["in_reply_to_screen_name"].toString());
|
||||
status.setFavorited(var["favorited"].toBool());
|
||||
|
||||
QVariantMap userMap = var["user"].toMap();
|
||||
QTweetUser user = variantMapToUserInfo(userMap);
|
||||
|
@@ -64,7 +64,7 @@ void QTweetFriendshipDestroy::unfollow(qint64 userid, bool includeEntities)
|
||||
|
||||
QNetworkRequest req(url);
|
||||
|
||||
QByteArray oauthHeader = oauthTwitter()->generateAuthorizationHeader(url, OAuth::GET);
|
||||
QByteArray oauthHeader = oauthTwitter()->generateAuthorizationHeader(url, OAuth::DELETE);
|
||||
req.setRawHeader(AUTH_HEADER, oauthHeader);
|
||||
|
||||
QNetworkReply *reply = oauthTwitter()->networkAccessManager()->deleteResource(req);
|
||||
@@ -92,7 +92,7 @@ void QTweetFriendshipDestroy::unfollow(const QString &screenName, bool includeEn
|
||||
|
||||
QNetworkRequest req(url);
|
||||
|
||||
QByteArray oauthHeader = oauthTwitter()->generateAuthorizationHeader(url, OAuth::GET);
|
||||
QByteArray oauthHeader = oauthTwitter()->generateAuthorizationHeader(url, OAuth::DELETE);
|
||||
req.setRawHeader(AUTH_HEADER, oauthHeader);
|
||||
|
||||
QNetworkReply *reply = oauthTwitter()->networkAccessManager()->deleteResource(req);
|
||||
|
@@ -69,7 +69,7 @@ void QTweetSearchResult::setCreatedAt(const QDateTime &dateTime)
|
||||
void QTweetSearchResult::setCreatedAt(const QString &twitterDate)
|
||||
{
|
||||
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);
|
||||
|
||||
QDate date = QDate::fromString(dateString);
|
||||
|
@@ -33,14 +33,28 @@
|
||||
|
||||
#define TWITTER_USERSTREAM_URL "https://userstream.twitter.com/2/user.json"
|
||||
|
||||
// ### TODO User Agent or X-User-Agent
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@@ -122,7 +93,9 @@ void QTweetUserStream::startFetching()
|
||||
m_reply = m_oauthTwitter->networkAccessManager()->get(req);
|
||||
connect(m_reply, SIGNAL(finished()), this, SLOT(replyFinished()));
|
||||
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()
|
||||
{
|
||||
if (!m_reply->error()) { //no error, reconnect
|
||||
qDebug() << "User stream closed ";
|
||||
|
||||
//sligh delay for reconnect
|
||||
m_backofftimer->setInterval(250);
|
||||
m_streamTryingReconnect = true;
|
||||
|
||||
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_reply->deleteLater();
|
||||
m_reply = 0;
|
||||
} else { //error, delete QNetworkReply
|
||||
m_reply->deleteLater();
|
||||
m_reply = 0;
|
||||
|
||||
qDebug() << "Exp backoff interval: " << nextInterval;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,30 +144,53 @@ void QTweetUserStream::replyReadyRead()
|
||||
{
|
||||
QByteArray response = m_reply->readAll();
|
||||
|
||||
//reset timer
|
||||
m_backofftimer->setInterval(0);
|
||||
#ifdef STREAM_LOGGER
|
||||
m_streamLog.write(response);
|
||||
m_streamLog.write("\n");
|
||||
#endif
|
||||
|
||||
//split to response to delimited and not delimited part
|
||||
int lastCarrReturn = response.lastIndexOf('\r');
|
||||
QByteArray rightNotDelimitedPart = response.mid(lastCarrReturn + 1);
|
||||
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 (m_streamTryingReconnect) {
|
||||
emit reconnected();
|
||||
m_streamTryingReconnect = false;
|
||||
}
|
||||
|
||||
if (rightNotDelimitedPart != QByteArray(1, '\n'))
|
||||
m_cashedResponse = rightNotDelimitedPart;
|
||||
else
|
||||
m_cashedResponse.clear();
|
||||
//set backoff timer to initial interval
|
||||
m_backofftimer->setInterval(20000);
|
||||
|
||||
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)
|
||||
@@ -187,6 +207,9 @@ void QTweetUserStream::parsingFinished(const QVariant &json, bool ok, const QStr
|
||||
{
|
||||
if (!ok) {
|
||||
qDebug() << "JSON parsing error: " << errorMsg;
|
||||
#ifdef STREAM_LOGGER
|
||||
m_streamLog.write("***** JSON parsing error *****\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -25,6 +25,10 @@
|
||||
#include <QNetworkReply>
|
||||
#include "qtweetlib_global.h"
|
||||
|
||||
#ifdef STREAM_LOGGER
|
||||
#include <QFile>
|
||||
#endif
|
||||
|
||||
class QNetworkAccessManager;
|
||||
class QNetworkReply;
|
||||
class OAuthTwitter;
|
||||
@@ -49,7 +53,6 @@ signals:
|
||||
* Emits stream elements
|
||||
*/
|
||||
void stream(const QByteArray& );
|
||||
|
||||
/**
|
||||
* Emits tweets (parsed) elements from stream
|
||||
*/
|
||||
@@ -68,14 +71,24 @@ signals:
|
||||
* Emits deletion of status in the stream
|
||||
*/
|
||||
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:
|
||||
void startFetching();
|
||||
|
||||
private slots:
|
||||
void replyError(QNetworkReply::NetworkError code);
|
||||
void replyFinished();
|
||||
void replyReadyRead();
|
||||
void replyTimeout();
|
||||
void parsingFinished(const QVariant& json, bool ok, const QString& errorMsg);
|
||||
|
||||
private:
|
||||
@@ -84,10 +97,16 @@ private:
|
||||
void parseDirectMessage(const QVariantMap& streamObject);
|
||||
void parseDeleteStatus(const QVariantMap& streamObject);
|
||||
|
||||
QByteArray m_cachedResponse;
|
||||
OAuthTwitter *m_oauthTwitter;
|
||||
QNetworkReply *m_reply;
|
||||
QTimer *m_backofftimer;
|
||||
QByteArray m_cashedResponse;
|
||||
QTimer *m_timeoutTimer;
|
||||
bool m_streamTryingReconnect;
|
||||
|
||||
#ifdef STREAM_LOGGER
|
||||
QFile m_streamLog;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // QTWEETUSERSTREAM_H
|
||||
|
Reference in New Issue
Block a user