From 87652eb774ec98d283c7448652d29a1eb21340bc Mon Sep 17 00:00:00 2001 From: Evgeniy Alekseev Date: Wed, 14 Sep 2016 11:32:40 +0300 Subject: [PATCH] add ability to upload telemetry to a server --- .../plugin/awtelemetryhandler.cpp | 132 +++++++++++++----- .../plugin/awtelemetryhandler.h | 11 +- sources/version.h.in | 2 + 3 files changed, 105 insertions(+), 40 deletions(-) diff --git a/sources/awesome-widget/plugin/awtelemetryhandler.cpp b/sources/awesome-widget/plugin/awtelemetryhandler.cpp index eae75c2..bb8d279 100644 --- a/sources/awesome-widget/plugin/awtelemetryhandler.cpp +++ b/sources/awesome-widget/plugin/awtelemetryhandler.cpp @@ -29,7 +29,7 @@ #include "awdebug.h" -AWTelemetryHandler::AWTelemetryHandler(QObject *parent) +AWTelemetryHandler::AWTelemetryHandler(QObject *parent, const QString clientId) : QObject(parent) { qCDebug(LOG_AW) << __PRETTY_FUNCTION__; @@ -42,6 +42,9 @@ AWTelemetryHandler::AWTelemetryHandler(QObject *parent) QStandardPaths::GenericDataLocation)); init(); + // override client id if any + if (!clientId.isEmpty()) + m_clientId = clientId; } @@ -82,49 +85,99 @@ bool AWTelemetryHandler::put(const QString group, const QString value) const QSettings settings(m_localFile, QSettings::IniFormat); settings.beginGroup(group); // values will be stored as num=value inside specified group - QString key - = QString("%1").arg(settings.childKeys().count(), 3, 10, QChar('0')); - settings.setValue(key, value); - settings.endGroup(); - - // sync settings - settings.sync(); - // check status - if (settings.status() != QSettings::NoError) + // load all values to memory + QStringList saved; + for (auto key : settings.childKeys()) + saved.append(settings.value(key).toString()); + // check if this value is already saved + if (saved.contains(value)) { + qCInfo(LOG_AW) << "Configuration" << value << "for group" << group + << "is already saved"; return false; - // rotate - return rotate(); -} - - -bool AWTelemetryHandler::rotate() const -{ - QSettings settings(m_localFile, QSettings::IniFormat); - - for (auto group : settings.childGroups()) { - QStringList data; - settings.beginGroup(group); - // load current data - for (auto key : settings.childKeys()) - data.append(settings.value(key).toString()); - // remove first item from list - while (data.count() > m_storeCount) - data.takeFirst(); - // clear values - settings.remove(QString("")); - // save new values - for (auto value : data) { - QString key = QString("%1").arg(settings.childKeys().count(), 3, 10, - QChar('0')); - settings.setValue(key, value); - } - settings.endGroup(); + } + saved.append(value); + // remove old ones + while (saved.count() > m_storeCount) + saved.takeFirst(); + // clear group + settings.remove(QString("")); + // and save now + for (auto value : saved) { + QString key = getKey(settings.childKeys().count()); + settings.setValue(key, value); } // sync settings + settings.endGroup(); settings.sync(); // return status - return (settings.status() == QSettings::NoError); + return (settings.status() != QSettings::NoError); +} + + +void AWTelemetryHandler::uploadTelemetry(const QString group, + const QString value) +{ + qCDebug(LOG_AW) << "Upload data with group" << group << "and value" + << value; + if (!m_uploadEnabled) { + qCInfo(LOG_AW) << "Upload disabled by configuration"; + return; + } + + QNetworkAccessManager *manager = new QNetworkAccessManager(nullptr); + connect(manager, SIGNAL(finished(QNetworkReply *)), this, + SLOT(telemetryReplyRecieved(QNetworkReply *))); + + QUrl url(REMOTE_TELEMETRY_URL); + url.setPort(REMOTE_TELEMETRY_PORT); + QNetworkRequest request(url); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + + // generate payload + QVariantMap payload; + payload[QString("api")] = AWTEAPI; + payload[QString("client_id")] = m_clientId; + payload[QString("metadata")] = value; + payload[QString("type")] = group; + // convert to QByteArray to send request + QByteArray data + = QJsonDocument::fromVariant(payload).toJson(QJsonDocument::Compact); + qCInfo(LOG_AW) << "Send request with body" << data.data() << "and size" + << data.size(); + + manager->post(request, data); +} + + +void AWTelemetryHandler::telemetryReplyRecieved(QNetworkReply *reply) +{ + if (reply->error() != QNetworkReply::NoError) { + qCWarning(LOG_AW) << "An error occurs" << reply->error() + << "with message" << reply->errorString(); + return; + } + + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(LOG_AW) << "Parse error" << error.errorString(); + return; + } + reply->deleteLater(); + + // convert to map + QVariantMap response = jsonDoc.toVariant().toMap(); + qCInfo(LOG_AW) << "Server reply on telemetry" + << response[QString("message")].toString(); +} + + +QString AWTelemetryHandler::getKey(const int count) const +{ + qCDebug(LOG_AW) << "Get key for keys count" << count; + + return QString("%1").arg(count, 3, 10, QChar('0')); } @@ -141,6 +194,9 @@ void AWTelemetryHandler::init() // count items to store m_storeCount = settings.value(QString("StoreHistory"), 100).toInt(); setConfiguration(QString("StoreHistory"), m_storeCount, false); + // check if upload enabled + m_uploadEnabled = settings.value(QString("Upload"), false).toBool(); + setConfiguration(QString("Upload"), m_uploadEnabled, false); settings.endGroup(); } diff --git a/sources/awesome-widget/plugin/awtelemetryhandler.h b/sources/awesome-widget/plugin/awtelemetryhandler.h index a5f2c35..fd51c56 100644 --- a/sources/awesome-widget/plugin/awtelemetryhandler.h +++ b/sources/awesome-widget/plugin/awtelemetryhandler.h @@ -22,6 +22,9 @@ #include #include +#define REMOTE_TELEMETRY_URL "http://arcanis.me/telemetry" +#define REMOTE_TELEMETRY_PORT 8080 + class QAbstractButton; class QNetworkReply; @@ -31,16 +34,19 @@ class AWTelemetryHandler : public QObject Q_OBJECT public: - explicit AWTelemetryHandler(QObject *parent = nullptr); + explicit AWTelemetryHandler(QObject *parent = nullptr, + const QString clientId = QString()); virtual ~AWTelemetryHandler(); Q_INVOKABLE QStringList get(const QString group) const; Q_INVOKABLE QString getLast(const QString group) const; Q_INVOKABLE bool put(const QString group, const QString value) const; - Q_INVOKABLE bool rotate() const; + Q_INVOKABLE void uploadTelemetry(const QString group, const QString value); private slots: + void telemetryReplyRecieved(QNetworkReply *reply); private: + QString getKey(const int count) const; void init(); bool setConfiguration(const QString key, const QVariant value, const bool override) const; @@ -48,6 +54,7 @@ private: QString m_genericConfig; QString m_localFile; int m_storeCount = 0; + bool m_uploadEnabled = false; }; diff --git a/sources/version.h.in b/sources/version.h.in index 2919140..74319cc 100644 --- a/sources/version.h.in +++ b/sources/version.h.in @@ -36,6 +36,8 @@ #define AWEWAPI 3 // formatter api version #define AWEFAPI 2 +// telemetry api version +#define AWTEAPI 1 // network requests timeout, ms #define REQUEST_TIMEOUT 3000 // available time keys