Skip to content

Commit

Permalink
'SendStatistics' operation implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
atiunov committed Apr 25, 2018
1 parent 8e6bd6c commit 1c8050d
Show file tree
Hide file tree
Showing 5 changed files with 312 additions and 2 deletions.
2 changes: 2 additions & 0 deletions src/libs/installer/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include "licenseoperation.h"
#include "settingsoperation.h"
#include "consumeoutputoperation.h"
#include "sendstatisticsoperation.h"

#include "lib7z_facade.h"
#include "utils.h"
Expand Down Expand Up @@ -165,6 +166,7 @@ void QInstaller::init()
factory.registerUpdateOperation<LicenseOperation>(QLatin1String("License"));
factory.registerUpdateOperation<ConsumeOutputOperation>(QLatin1String("ConsumeOutput"));
factory.registerUpdateOperation<SettingsOperation>(QLatin1String("Settings"));
factory.registerUpdateOperation<SendStatisticsOperation>(QLatin1String("SendStatistics"));

FileDownloaderFactory::setFollowRedirects(true);

Expand Down
7 changes: 5 additions & 2 deletions src/libs/installer/installer.pro
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,9 @@ HEADERS += packagemanagercore.h \
lib7z_guid.h \
lib7z_create.h \
lib7z_extract.h \
lib7z_list.h
lib7z_list.h \
sendstatisticsoperation_p.h \
sendstatisticsoperation.h

SOURCES += packagemanagercore.cpp \
packagemanagercore_p.cpp \
Expand Down Expand Up @@ -206,7 +208,8 @@ SOURCES += packagemanagercore.cpp \
serverauthenticationdialog.cpp \
keepaliveobject.cpp \
systeminfo.cpp \
packagesource.cpp
packagesource.cpp \
sendstatisticsoperation.cpp

FORMS += proxycredentialsdialog.ui \
serverauthenticationdialog.ui
Expand Down
95 changes: 95 additions & 0 deletions src/libs/installer/sendstatisticsoperation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
* UGENE - Integrated Bioinformatics Tools.
* Copyright (C) 2008-2018 UniPro <ugene@unipro.ru>
* http://ugene.net
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/

#include "packagemanagercore.h"
#include "packagemanagerproxyfactory.h"
#include "sendstatisticsoperation.h"
#include "sendstatisticsoperation_p.h"

#include <QDebug>
#include <QThreadPool>

using namespace QInstaller;

SendStatisticsOperation::SendStatisticsOperation(PackageManagerCore *core)
: UpdateOperation(core)
{
setName(QLatin1String("SendStatistics"));
}

void SendStatisticsOperation::backup()
{
// Do nothing
}

bool SendStatisticsOperation::performOperation()
{
if (!checkArgumentCount(1, INT_MAX)) {
qDebug() << "Failed to send statistics because of invalid arguments count: " << arguments().size();
// Do not interrupt the installation
return true;
}

const QStringList args = arguments();
const QUrl url = args.at(0);
QMap<QByteArray, QByteArray> additionalHeaders;
for (int i = 1; i < args.size(); ++i) {
QStringList pair = args.at(i).split(QLatin1String("="));
if (2 != pair.size()) {
qDebug() << "Failed to parse argument during statistics sending: " << args.at(i);
continue;
}

additionalHeaders.insert(pair.first().toLatin1(), pair.last().toLatin1());
}

Receiver receiver;

Runnable *runnable = new Runnable(url, additionalHeaders, packageManager()->proxyFactory());
QObject::connect(runnable, &Runnable::finished, &receiver, &Receiver::runnableFinished/*, Qt::QueuedConnection*/);

QEventLoop loop;
QObject::connect(&receiver, &Receiver::finished, &loop, &QEventLoop::quit);
if (QThreadPool::globalInstance()->tryStart(runnable)) {
loop.exec();
} else {
// HACK: In case there is no availabe thread we should call it directly.
runnable->run();
receiver.runnableFinished(true, QString());
}

if (!receiver.success()) {
// It's pity, but it's not critical
qDebug() << "Failed to send statistics with the next arguments: " << args.join(QLatin1String(", "));
qDebug() << "Because of error: " << receiver.errorString();
}
return true;
}

bool SendStatisticsOperation::undoOperation()
{
return true;
}

bool SendStatisticsOperation::testOperation()
{
return true;
}
47 changes: 47 additions & 0 deletions src/libs/installer/sendstatisticsoperation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* UGENE - Integrated Bioinformatics Tools.
* Copyright (C) 2008-2018 UniPro <ugene@unipro.ru>
* http://ugene.net
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/

#ifndef SENDSTATISTICSOPERATION_H
#define SENDSTATISTICSOPERATION_H

#include "qinstallerglobal.h"

namespace QInstaller {

class SendStatisticsOperation : public Operation
{
Q_DECLARE_TR_FUNCTIONS(QInstaller::SendStatisticsOperation)
public:
explicit SendStatisticsOperation(PackageManagerCore *core);

void backup();
bool performOperation();
bool undoOperation();
bool testOperation();

private:
class Runnable;
class Receiver;
};

} // namespace

#endif // SENDSTATISTICSOPERATION_H
163 changes: 163 additions & 0 deletions src/libs/installer/sendstatisticsoperation_p.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/**
* UGENE - Integrated Bioinformatics Tools.
* Copyright (C) 2008-2018 UniPro <ugene@unipro.ru>
* http://ugene.net
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/

#ifndef SENDSTATISTICSOPERATION_P_H
#define SENDSTATISTICSOPERATION_P_H

#include "sendstatisticsoperation.h"

#include <QAuthenticator>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QRunnable>
#include <QThread>
#include <QTimer>

namespace QInstaller {

class SendStatisticsOperation::Runnable : public QObject, public QRunnable
{
Q_OBJECT
Q_DISABLE_COPY(Runnable)

public:
Runnable(const QUrl &url, const QMap<QByteArray, QByteArray> &additionalHeaders, QNetworkProxyFactory *proxyFactory)
: m_url(url)
, m_additionalHeaders(additionalHeaders)
, m_proxyFactory(proxyFactory)
, http(NULL)
{
}

void run()
{
QNetworkAccessManager manager;
QEventLoop eventLoop;
connect(this, &Runnable::finished, &eventLoop, &QEventLoop::quit);

#ifndef QT_NO_SSL
connect(&manager, &QNetworkAccessManager::sslErrors,
this, &Runnable::onSslErrors);
#endif
connect(&manager, &QNetworkAccessManager::authenticationRequired,
this, &Runnable::onAuthenticationRequired);
connect(&manager, &QNetworkAccessManager::networkAccessibleChanged,
this, &Runnable::onNetworkAccessibleChanged);

manager.setProxyFactory(m_proxyFactory);

http = manager.get(prepareRequest());
connect(http, SIGNAL(finished()), this, SLOT(httpReqFinished()));

QTimer::singleShot(TIMEOUT, this, &Runnable::timeout);
eventLoop.exec();
}

signals:
void finished(bool success, const QString &errorString);

private slots:
void onSslErrors(QNetworkReply *, const QList<QSslError> &errors) {
QString errorString = tr("The following SSL errors encountered:");
foreach (const QSslError &error, errors) {
errorString += QLatin1Char('\n') + error.errorString();
}
emit finished(false, errorString);
}

void onAuthenticationRequired() {
emit finished(false, tr("The server asks for an authentification, do not bother the user with it"));
}

void onNetworkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible) {
if (QNetworkAccessManager::NotAccessible == accessible) {
emit finished(false, tr("The network becomes not accessable, cancel the operation"));
}
}

void httpReqFinished() {
if (QNetworkReply::NoError == http->error()) {
emit finished(true, QLatin1String());
} else {
emit finished(false, http->errorString());
}
}

void timeout() {
http->abort();
emit finished(false, tr("Operation cancelled: timeout"));
}

private:
QNetworkRequest prepareRequest() const
{
QNetworkRequest request(m_url);
QMapIterator<QByteArray, QByteArray> it(m_additionalHeaders);
while (it.hasNext()) {
request.setRawHeader(it.key(), it.value());
}

return request;
}

QUrl m_url;
QMap<QByteArray, QByteArray> m_additionalHeaders;
QNetworkProxyFactory *m_proxyFactory;
QNetworkReply *http;

static const int TIMEOUT = 5000;
};

class SendStatisticsOperation::Receiver : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Receiver)

public:
Receiver() = default;

bool success() const {
return m_success;
}

QString errorString() const {
return m_errorString;
}

public slots:
void runnableFinished(bool ok, const QString &msg)
{
m_success = ok;
m_errorString = msg;
emit finished();
}

signals:
void finished();

private:
bool m_success = false;
QString m_errorString;
};

}

#endif // SENDSTATISTICSOPERATION_P_H

0 comments on commit 1c8050d

Please sign in to comment.