From 2f8c752d1fe9976fdbd683d34ae3dcbf4e797591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 20 Nov 2016 12:32:27 +0100 Subject: NOISSUE reformat and sanitize ganalytics --- libraries/ganalytics/src/ganalytics_worker.cpp | 252 +++++++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 libraries/ganalytics/src/ganalytics_worker.cpp (limited to 'libraries/ganalytics/src/ganalytics_worker.cpp') diff --git a/libraries/ganalytics/src/ganalytics_worker.cpp b/libraries/ganalytics/src/ganalytics_worker.cpp new file mode 100644 index 00000000..3dbbb50a --- /dev/null +++ b/libraries/ganalytics/src/ganalytics_worker.cpp @@ -0,0 +1,252 @@ +#include "ganalytics.h" +#include "ganalytics_worker.h" +#include "sys.h" + +#include +#include +#include + +#include +#include + +const QLatin1String GAnalyticsWorker::dateTimeFormat("yyyy,MM,dd-hh:mm::ss:zzz"); + +GAnalyticsWorker::GAnalyticsWorker(GAnalytics *parent) + : QObject(parent), q(parent), m_logLevel(GAnalytics::Error), m_isSending(false) +{ + m_appName = QCoreApplication::instance()->applicationName(); + m_appVersion = QCoreApplication::instance()->applicationVersion(); + m_request.setUrl(QUrl("https://www.google-analytics.com/collect")); + m_request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + m_request.setHeader(QNetworkRequest::UserAgentHeader, getUserAgent()); + + m_language = QLocale::system().name().toLower().replace("_", "-"); + m_screenResolution = getScreenResolution(); + + m_timer.start(30000); + connect(&m_timer, &QTimer::timeout, this, &GAnalyticsWorker::postMessage); +} + +void GAnalyticsWorker::logMessage(GAnalytics::LogLevel level, const QString &message) +{ + if (m_logLevel > level) + { + return; + } + + qDebug() << "[Analytics]" << message; +} + +/** + * Build the POST query. Adds all parameter to the query + * which are used in every POST. + * @param type Type of POST message. The event which is to post. + * @return query Most used parameter in a query for a POST. + */ +QUrlQuery GAnalyticsWorker::buildStandardPostQuery(const QString &type) +{ + QUrlQuery query; + query.addQueryItem("v", "1"); + query.addQueryItem("tid", m_trackingID); + query.addQueryItem("cid", m_clientID); + if (!m_userID.isEmpty()) + { + query.addQueryItem("uid", m_userID); + } + query.addQueryItem("t", type); + query.addQueryItem("ul", m_language); + query.addQueryItem("vp", m_viewportSize); + query.addQueryItem("sr", m_screenResolution); + return query; +} + +/** + * Get primary screen resolution. + * @return A QString like "800x600". + */ +QString GAnalyticsWorker::getScreenResolution() +{ + QScreen *screen = QGuiApplication::primaryScreen(); + QSize size = screen->size(); + + return QString("%1x%2").arg(size.width()).arg(size.height()); +} + +/** + * Try to gain information about the system where this application + * is running. It needs to get the name and version of the operating + * system, the language and screen resolution. + * All this information will be send in POST messages. + * @return agent A QString with all the information formatted for a POST message. + */ +QString GAnalyticsWorker::getUserAgent() +{ + QString locale = QLocale::system().name(); + QString system = Sys::getSystemInfo(); + + return QString("%1/%2 (%3; %4) GAnalytics/1.0 (Qt/%5)").arg(m_appName).arg(m_appVersion).arg(system).arg(locale).arg(QT_VERSION_STR); +} + +/** + * The message queue contains a list of QueryBuffer object. + * QueryBuffer holds a QUrlQuery object and a QDateTime object. + * These both object are freed from the buffer object and + * inserted as QString objects in a QList. + * @return dataList The list with concartinated queue data. + */ +QList GAnalyticsWorker::persistMessageQueue() +{ + QList dataList; + foreach (QueryBuffer buffer, m_messageQueue) + { + dataList << buffer.postQuery.toString(); + dataList << buffer.time.toString(dateTimeFormat); + } + return dataList; +} + +/** + * Reads persistent messages from a file. + * Gets all message data as a QList. + * Two lines in the list build a QueryBuffer object. + */ +void GAnalyticsWorker::readMessagesFromFile(const QList &dataList) +{ + QListIterator iter(dataList); + while (iter.hasNext()) + { + QString queryString = iter.next(); + QString dateString = iter.next(); + QUrlQuery query; + query.setQuery(queryString); + QDateTime dateTime = QDateTime::fromString(dateString, dateTimeFormat); + QueryBuffer buffer; + buffer.postQuery = query; + buffer.time = dateTime; + m_messageQueue.enqueue(buffer); + } +} + +/** + * Takes a QUrlQuery object and wrapp it together with + * a QTime object into a QueryBuffer struct. These struct + * will be stored in the message queue. + */ +void GAnalyticsWorker::enqueQueryWithCurrentTime(const QUrlQuery &query) +{ + QueryBuffer buffer; + buffer.postQuery = query; + buffer.time = QDateTime::currentDateTime(); + + m_messageQueue.enqueue(buffer); +} + +/** + * Change status of class. Emit signal that status was changed. + */ +void GAnalyticsWorker::setIsSending(bool doSend) +{ + if (doSend) + { + m_timer.stop(); + } + else + { + m_timer.start(); + } + + bool changed = (m_isSending != doSend); + + m_isSending = doSend; + + if (changed) + { + emit q->isSendingChanged(m_isSending); + } +} + +/** + * This function is called by a timer interval. + * The function tries to send a messages from the queue. + * If message was successfully send then this function + * will be called back to send next message. + * If message queue contains more than one message then + * the connection will kept open. + * The message POST is asyncroniously when the server + * answered a signal will be emitted. + */ +void GAnalyticsWorker::postMessage() +{ + if (m_messageQueue.isEmpty()) + { + setIsSending(false); + return; + } + else + { + setIsSending(true); + } + + QString connection = "close"; + if (m_messageQueue.count() > 1) + { + connection = "keep-alive"; + } + + QueryBuffer buffer = m_messageQueue.head(); + QDateTime sendTime = QDateTime::currentDateTime(); + qint64 timeDiff = buffer.time.msecsTo(sendTime); + + if (timeDiff > fourHours) + { + // too old. + m_messageQueue.dequeue(); + emit postMessage(); + return; + } + + buffer.postQuery.addQueryItem("qt", QString::number(timeDiff)); + m_request.setRawHeader("Connection", connection.toUtf8()); + m_request.setHeader(QNetworkRequest::ContentLengthHeader, buffer.postQuery.toString().length()); + + // Create a new network access manager if we don't have one yet + if (networkManager == NULL) + { + networkManager = new QNetworkAccessManager(this); + } + + QNetworkReply *reply = networkManager->post(m_request, buffer.postQuery.query(QUrl::EncodeUnicode).toUtf8()); + connect(reply, SIGNAL(finished()), this, SLOT(postMessageFinished())); +} + +/** + * NetworkAccsessManager has finished to POST a message. + * If POST message was successfully send then the message + * query should be removed from queue. + * SIGNAL "postMessage" will be emitted to send next message + * if there is any. + * If message couldn't be send then next try is when the + * timer emits its signal. + */ +void GAnalyticsWorker::postMessageFinished() +{ + QNetworkReply *reply = qobject_cast(sender()); + + int httpStausCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + if (httpStausCode < 200 || httpStausCode > 299) + { + logMessage(GAnalytics::Error, QString("Error posting message: %s").arg(reply->errorString())); + + // An error ocurred. + setIsSending(false); + return; + } + else + { + logMessage(GAnalytics::Debug, "Message sent"); + } + + m_messageQueue.dequeue(); + postMessage(); + reply->deleteLater(); +} -- cgit v1.2.3