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:
@@ -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);
|
||||||
|
@@ -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);
|
||||||
|
@@ -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);
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user