fix(cpn): sounds processing extra files and cancel update processes earlier (#5354)
Co-authored-by: elecpower <elecpower@users.noreply.github.com>
This commit is contained in:
@@ -212,3 +212,10 @@ void ProgressWidget::forceKeepOpen(bool value)
|
||||
{
|
||||
emit keepOpen(value);
|
||||
}
|
||||
|
||||
void ProgressWidget::refresh()
|
||||
{
|
||||
ui->info->update();
|
||||
ui->progressBar->update();
|
||||
ui->textEdit->update();
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ class ProgressWidget : public QWidget
|
||||
void stop();
|
||||
void clearDetails() const;
|
||||
void forceKeepOpen(bool value);
|
||||
void refresh();
|
||||
|
||||
signals:
|
||||
void detailsToggled();
|
||||
|
||||
@@ -27,14 +27,17 @@
|
||||
#include <QFileInfo>
|
||||
#include <QDebug>
|
||||
#include <QWidget>
|
||||
#include <QApplication>
|
||||
|
||||
MinizInterface::MinizInterface(ProgressWidget * progress, const ProgressCalcMethod progressMethod, const int & logLevel) :
|
||||
QObject(nullptr),
|
||||
progress(progress),
|
||||
progressMethod(progressMethod),
|
||||
progressValue(0),
|
||||
logLevel(logLevel),
|
||||
path(""),
|
||||
archiveFile("")
|
||||
archiveFile(""),
|
||||
stopping(false)
|
||||
{
|
||||
reportProgress(tr("Progress calculation method: file %1").arg(progressMethod == PCM_COUNT ? tr("count") : tr("size")), QtDebugMsg);
|
||||
}
|
||||
@@ -171,8 +174,10 @@ bool MinizInterface::addFileToArchive(const QString & path)
|
||||
|
||||
bool MinizInterface::unzipArchiveToPath(const QString & archiveFile, const QString & destinationPath)
|
||||
{
|
||||
QFileInfo file(archiveFile);
|
||||
|
||||
if (progress)
|
||||
progress->setInfo(tr("Decompressing %1").arg(archiveFile));
|
||||
progress->setInfo(tr("Decompressing %1").arg(file.fileName()));
|
||||
else
|
||||
qDebug() << QString("Decompressing %1 to %2").arg(archiveFile, destinationPath);
|
||||
|
||||
@@ -212,6 +217,12 @@ bool MinizInterface::unzipArchiveToPath(const QString & archiveFile, const QStri
|
||||
}
|
||||
|
||||
for (int i = 0; i < fileCount; i++) {
|
||||
if (isStopping()) {
|
||||
mz_zip_reader_end(&zip_archive);
|
||||
reportProgress(tr("Decompression interrupted"), QtWarningMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mz_zip_reader_file_stat(&zip_archive, i, &file_stat)) {
|
||||
mz_zip_reader_end(&zip_archive);
|
||||
reportProgress(tr("Unable to obtain file status for index: %1").arg(i), QtFatalMsg);
|
||||
@@ -254,6 +265,8 @@ bool MinizInterface::unzipArchiveToPath(const QString & archiveFile, const QStri
|
||||
progress->setValue(progressValue);
|
||||
|
||||
reportProgress(tr("Extracted file: %1").arg(file_stat.m_filename), QtDebugMsg);
|
||||
// to assist in responsiveness and allow stop signal to be received and processed
|
||||
QApplication::processEvents();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,3 +303,8 @@ void MinizInterface::reportProgress(const QString & text, const int & type, bool
|
||||
qDebug() << text;
|
||||
}
|
||||
}
|
||||
|
||||
void MinizInterface::stop()
|
||||
{
|
||||
stopping = true;
|
||||
}
|
||||
|
||||
@@ -28,9 +28,9 @@
|
||||
|
||||
class ProgressWidget;
|
||||
|
||||
class MinizInterface
|
||||
class MinizInterface : public QObject
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(MinizInterface)
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum ProgressCalcMethod {
|
||||
@@ -44,6 +44,9 @@ class MinizInterface
|
||||
bool zipPathToFile(const QString & sourcePath, const QString & archiveFile, bool append = true);
|
||||
bool unzipArchiveToPath(const QString & archiveFile, const QString & destinationPath);
|
||||
|
||||
public slots:
|
||||
void stop();
|
||||
|
||||
private:
|
||||
ProgressWidget *progress;
|
||||
ProgressCalcMethod progressMethod;
|
||||
@@ -51,10 +54,12 @@ class MinizInterface
|
||||
int logLevel;
|
||||
QString path;
|
||||
QString archiveFile;
|
||||
bool stopping;
|
||||
|
||||
mz_zip_archive zip_archive;
|
||||
|
||||
bool addFileToArchive(const QString & path);
|
||||
bool createDirectory(const QString & path);
|
||||
void reportProgress(const QString & text, const int & type = QtInfoMsg, bool richText = false);
|
||||
bool isStopping() { return stopping; }
|
||||
};
|
||||
|
||||
@@ -106,6 +106,15 @@ bool AssetsRawItemModel::setDownloadName(const int id, const QString name)
|
||||
return setValue(id, RIMR_DownloadName, QVariant(name));
|
||||
}
|
||||
|
||||
bool AssetsRawItemModel::resetFlags()
|
||||
{
|
||||
for (int i = 0; i < rowCount(); i++) {
|
||||
item(i)->setData(0, RIMR_Flags);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
AssetsFilteredItemModel
|
||||
*/
|
||||
@@ -320,3 +329,8 @@ bool RepoAssets::setDownloadName(const QString name)
|
||||
{
|
||||
return m_rawItemModel->setDownloadName(id(), name);
|
||||
}
|
||||
|
||||
bool RepoAssets::resetFlags()
|
||||
{
|
||||
return m_rawItemModel->resetFlags();
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ class AssetsRawItemModel : public RepoRawItemModel
|
||||
|
||||
bool setDownloadUrl(const int id, const QString url);
|
||||
bool setDownloadName(const int id, const QString name);
|
||||
bool resetFlags();
|
||||
|
||||
private:
|
||||
QObject *m_parentRepo; // cannot use Repo class from repo.h as compile error due to cyclic headers
|
||||
@@ -93,16 +94,22 @@ class RepoAssets : public QObject, public RepoMetaData
|
||||
bool getJson(const QString assetName, QJsonDocument * json);
|
||||
const QString name() const;
|
||||
const QString name(const int row);
|
||||
|
||||
bool setCopyFilter(const QString filter);
|
||||
|
||||
bool setSubDirectory(const QString path);
|
||||
const QString subDirectory() const;
|
||||
|
||||
bool setDownloadUrl(const QString url);
|
||||
const QString downloadUrl() const;
|
||||
const QString downloadUrl(const int row);
|
||||
|
||||
bool setDownloadName(const QString name);
|
||||
const QString downloadName() const;
|
||||
const QString downloadName(const int row);
|
||||
|
||||
bool resetFlags();
|
||||
|
||||
signals:
|
||||
void idChanged(int id);
|
||||
|
||||
|
||||
@@ -25,11 +25,10 @@
|
||||
#include "eeprominterface.h"
|
||||
#include "flashfirmwaredialog.h"
|
||||
|
||||
constexpr char STATUS_UNKNOWN[] {"STATUS_UNKNOWN"};
|
||||
constexpr char STATUS_WAITING_FOR_BUILD[] {"WAITING_FOR_BUILD"};
|
||||
constexpr char STATUS_BUILD_IN_PROGRESS[] {"BUILD_IN_PROGRESS"};
|
||||
constexpr char STATUS_BUILD_SUCCESS[] {"BUILD_SUCCESS"};
|
||||
// constexpr char STATUS_BUILD_ERROR[] {"BUILD_ERROR"};
|
||||
// these must match text strings in server response
|
||||
constexpr char CLOUD_BUILD_WAITING[] {"WAITING_FOR_BUILD"};
|
||||
constexpr char CLOUD_BUILD_IN_PROGRESS[] {"BUILD_IN_PROGRESS"};
|
||||
constexpr char CLOUD_BUILD_SUCCESS[] {"BUILD_SUCCESS"};
|
||||
|
||||
UpdateCloudBuild::UpdateCloudBuild(QWidget * parent) :
|
||||
UpdateInterface(parent, CID_CloudBuild, tr("CloudBuild"), Repo::REPO_TYPE_BUILD,
|
||||
@@ -48,6 +47,38 @@ UpdateCloudBuild::~UpdateCloudBuild()
|
||||
delete m_docResp;
|
||||
}
|
||||
|
||||
QString UpdateCloudBuild::statusToString(const int status)
|
||||
{
|
||||
switch (status) {
|
||||
case STATUS_WAITING:
|
||||
return tr("waiting");
|
||||
case STATUS_IN_PROGRESS:
|
||||
return tr("in progress");
|
||||
case STATUS_SUCCESS:
|
||||
return tr("success");
|
||||
case STATUS_ERROR:
|
||||
return tr("error");
|
||||
case STATUS_TIMEOUT:
|
||||
return tr("timeout");
|
||||
case STATUS_CANCELLED:
|
||||
return tr("cancelled");
|
||||
default:
|
||||
return tr("unknown");
|
||||
}
|
||||
}
|
||||
|
||||
int UpdateCloudBuild::cloudStatusToInt(const QString status)
|
||||
{
|
||||
if (status == QString(CLOUD_BUILD_WAITING))
|
||||
return STATUS_WAITING;
|
||||
else if (status == QString(CLOUD_BUILD_IN_PROGRESS))
|
||||
return STATUS_IN_PROGRESS;
|
||||
else if (status == QString(CLOUD_BUILD_SUCCESS))
|
||||
return STATUS_SUCCESS;
|
||||
else
|
||||
return STATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
void UpdateCloudBuild::assetSettingsInit()
|
||||
{
|
||||
if (!isSettingsIndexValid())
|
||||
@@ -189,8 +220,8 @@ int UpdateCloudBuild::asyncInstall()
|
||||
|
||||
bool UpdateCloudBuild::buildFlaggedAsset(const int row)
|
||||
{
|
||||
m_jobStatus = STATUS_UNKNOWN;
|
||||
m_buildFlags.clear();
|
||||
m_jobStatus.clear();
|
||||
m_profileOpts.clear();
|
||||
m_radio = repo()->assets()->name(row);
|
||||
|
||||
@@ -289,7 +320,7 @@ bool UpdateCloudBuild::buildFlaggedAsset(const int row)
|
||||
if (params()->logLevel == QtDebugMsg)
|
||||
network()->saveJsonDocToFile(docBody, QString("%1/%2_body.txt").arg(m_logDir).arg(m_radio));
|
||||
|
||||
network()->submitRequest(tr("Submit firmware build"), repo()->urlJobs(), docBody, m_docResp);
|
||||
network()->submitRequest(tr("Submit build request"), repo()->urlJobs(), docBody, m_docResp);
|
||||
|
||||
if (params()->logLevel == QtDebugMsg)
|
||||
network()->saveBufferToFile(QString("%1/%2_buffer.txt").arg(m_logDir).arg(m_radio));
|
||||
@@ -318,15 +349,18 @@ bool UpdateCloudBuild::buildFlaggedAsset(const int row)
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
m_jobStatus = obj.value("status").toString(QString(STATUS_UNKNOWN));
|
||||
m_jobStatus = cloudStatusToInt(obj.value("status").toString());
|
||||
}
|
||||
|
||||
if (isStatusInProgress())
|
||||
waitForBuildFinish();
|
||||
|
||||
status()->reportProgress(tr("Firmware build finished status: %1").arg(m_jobStatus));
|
||||
status()->reportProgress(tr("Build finish status: %1").arg(statusToString(m_jobStatus)));
|
||||
|
||||
if (m_jobStatus == QString(STATUS_BUILD_SUCCESS) && setAssetDownload())
|
||||
// ensure progress bar not in wait state
|
||||
status()->setMaximum(100);
|
||||
|
||||
if (m_jobStatus == STATUS_SUCCESS && setAssetDownload())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -334,22 +368,25 @@ bool UpdateCloudBuild::buildFlaggedAsset(const int row)
|
||||
|
||||
void UpdateCloudBuild::cancel()
|
||||
{
|
||||
status()->reportProgress(tr("Build firmware cancelled"), QtWarningMsg);
|
||||
// this does not cancel the build job on the server but only interrupts the client side
|
||||
status()->reportProgress(tr("Build cancelled"), QtWarningMsg);
|
||||
m_jobStatus = STATUS_CANCELLED;
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void UpdateCloudBuild::checkStatus()
|
||||
{
|
||||
if (m_buildStartTime.secsTo(QTime::currentTime()) > 180) {
|
||||
status()->reportProgress(tr("Build firmware timeout"), QtWarningMsg);
|
||||
status()->reportProgress(tr("Build timeout. Retry later."), QtWarningMsg);
|
||||
m_jobStatus = STATUS_TIMEOUT;
|
||||
cleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
getStatus();
|
||||
|
||||
if (!isStatusInProgress())
|
||||
cleanup();
|
||||
|
||||
}
|
||||
|
||||
void UpdateCloudBuild::cleanup()
|
||||
@@ -363,7 +400,7 @@ void UpdateCloudBuild::cleanup()
|
||||
|
||||
bool UpdateCloudBuild::getStatus()
|
||||
{
|
||||
m_jobStatus = QString(STATUS_UNKNOWN);
|
||||
m_jobStatus = STATUS_UNKNOWN;
|
||||
QJsonDocument *docBody = new QJsonDocument(*m_objBody);
|
||||
|
||||
if (m_docResp)
|
||||
@@ -376,9 +413,9 @@ bool UpdateCloudBuild::getStatus()
|
||||
network()->saveJsonDocToFile(m_docResp, QString("%1/%2_status_%3.txt").arg(m_logDir).arg(m_radio).arg(QTime::currentTime().toString("hhmmss")));
|
||||
|
||||
if (m_docResp->isObject())
|
||||
m_jobStatus = m_docResp->object().value("status").toString(QString(STATUS_UNKNOWN));
|
||||
m_jobStatus = cloudStatusToInt(m_docResp->object().value("status").toString());
|
||||
|
||||
if (m_jobStatus == QString(STATUS_UNKNOWN)) {
|
||||
if (m_jobStatus == STATUS_UNKNOWN) {
|
||||
status()->reportProgress(tr("Build status unknown"), QtCriticalMsg);
|
||||
return false;
|
||||
}
|
||||
@@ -388,7 +425,7 @@ bool UpdateCloudBuild::getStatus()
|
||||
|
||||
bool UpdateCloudBuild::isStatusInProgress()
|
||||
{
|
||||
if (m_jobStatus == QString(STATUS_WAITING_FOR_BUILD) || m_jobStatus == QString(STATUS_BUILD_IN_PROGRESS))
|
||||
if (m_jobStatus == STATUS_WAITING || m_jobStatus == STATUS_IN_PROGRESS)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -451,15 +488,16 @@ bool UpdateCloudBuild::stringExists(const QJsonObject & parent, const QString ch
|
||||
|
||||
void UpdateCloudBuild::waitForBuildFinish()
|
||||
{
|
||||
status()->progressMessage(tr("Waiting for firmware build to finish..."));
|
||||
status()->progressMessage(tr("Waiting for build to finish..."));
|
||||
status()->setMaximum(0); // sets progress bar to wait state
|
||||
m_timer.setInterval(2000); // check status every 2 seconds
|
||||
|
||||
connect(this, &UpdateInterface::stop, this, &UpdateCloudBuild::cancel);
|
||||
connect(this, &UpdateInterface::stopping, this, &UpdateCloudBuild::cancel);
|
||||
connect(&m_timer, &QTimer::timeout, this, &UpdateCloudBuild::checkStatus);
|
||||
|
||||
m_timer.start();
|
||||
m_eventLoop.exec();
|
||||
|
||||
disconnect(this, &UpdateInterface::stop, this, &UpdateCloudBuild::cancel);
|
||||
disconnect(&m_timer, nullptr);
|
||||
disconnect(&m_timer, &QTimer::timeout, this, &UpdateCloudBuild::checkStatus);
|
||||
disconnect(this, &UpdateInterface::stopping, this, &UpdateCloudBuild::cancel);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,16 @@ class UpdateCloudBuild: public UpdateInterface
|
||||
Q_DECLARE_TR_FUNCTIONS(UpdateCloudBuild)
|
||||
|
||||
public:
|
||||
enum ProcessStatus {
|
||||
STATUS_UNKNOWN,
|
||||
STATUS_WAITING,
|
||||
STATUS_IN_PROGRESS,
|
||||
STATUS_SUCCESS,
|
||||
STATUS_ERROR,
|
||||
STATUS_TIMEOUT,
|
||||
STATUS_CANCELLED
|
||||
};
|
||||
Q_ENUM(ProcessStatus)
|
||||
|
||||
explicit UpdateCloudBuild(QWidget * parent);
|
||||
virtual ~UpdateCloudBuild();
|
||||
@@ -53,7 +63,7 @@ class UpdateCloudBuild: public UpdateInterface
|
||||
QString m_logDir;
|
||||
QString m_buildFlags;
|
||||
QTime m_buildStartTime;
|
||||
QString m_jobStatus;
|
||||
int m_jobStatus;
|
||||
QStringList m_profileOpts;
|
||||
QString m_radio;
|
||||
|
||||
@@ -69,4 +79,6 @@ class UpdateCloudBuild: public UpdateInterface
|
||||
bool isStatusInProgress();
|
||||
bool setAssetDownload();
|
||||
void waitForBuildFinish();
|
||||
static QString statusToString(const int status);
|
||||
static int cloudStatusToInt(const QString status);
|
||||
};
|
||||
|
||||
@@ -130,11 +130,16 @@ int UpdateInterface::build()
|
||||
|
||||
bool UpdateInterface::buildFlaggedAssets()
|
||||
{
|
||||
if (!isOkay())
|
||||
return true;
|
||||
|
||||
m_repo->assets()->setFilterFlags(UPDFLG_Build);
|
||||
m_status->reportProgress(tr("Asset filter applied: %1 - %2 found").arg(updateFlagToString(UPDFLG_Build)).arg(m_repo->assets()->count()), QtDebugMsg);
|
||||
|
||||
for (int i = 0; i < m_repo->assets()->count(); ++i) {
|
||||
if (!buildFlaggedAsset(i))
|
||||
if (!isOkay())
|
||||
return true;
|
||||
else if (!buildFlaggedAsset(i))
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -211,9 +216,11 @@ bool UpdateInterface::copyFiles()
|
||||
|
||||
int cnt = 0;
|
||||
|
||||
processEvents();
|
||||
|
||||
//m_status->reportProgress(tr("Calculating number of files"), QtDebugMsg);
|
||||
|
||||
while (itcnt.hasNext())
|
||||
while (isOkay() && itcnt.hasNext())
|
||||
{
|
||||
QFileInfo src(itcnt.next());
|
||||
|
||||
@@ -229,7 +236,9 @@ bool UpdateInterface::copyFiles()
|
||||
|
||||
cnt = 0;
|
||||
|
||||
while (itfiles.hasNext())
|
||||
processEvents();
|
||||
|
||||
while (isOkay() && itfiles.hasNext())
|
||||
{
|
||||
QFileInfo src(itfiles.next());
|
||||
|
||||
@@ -254,6 +263,7 @@ bool UpdateInterface::copyFiles()
|
||||
m_status->reportProgress(tr("Copied %1 to %2").arg(src.fileName()).arg(dest.fileName()), QtDebugMsg);
|
||||
cnt++;
|
||||
m_status->setValue(cnt);
|
||||
processEvents();
|
||||
}
|
||||
|
||||
if (!cnt) {
|
||||
@@ -264,17 +274,23 @@ bool UpdateInterface::copyFiles()
|
||||
m_status->setValue(m_status->maximum());
|
||||
m_status->reportProgress(tr("Files copied: %1").arg(cnt), QtInfoMsg);
|
||||
|
||||
if (!isOkay())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UpdateInterface::copyFlaggedAssets()
|
||||
{
|
||||
if (!isOkay())
|
||||
return false;
|
||||
|
||||
m_repo->assets()->setFilterFlags(UPDFLG_CopyDest);
|
||||
m_status->reportProgress(tr("Asset filter applied: %1 - %2 found").arg(updateFlagToString(UPDFLG_CopyDest)).arg(m_repo->assets()->count()), QtDebugMsg);
|
||||
|
||||
for (int i = 0; i < m_repo->assets()->count(); ++i) {
|
||||
m_repo->assets()->getSetId(i);
|
||||
if (!copyAsset())
|
||||
if ( !isOkay() || !copyAsset())
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -307,7 +323,9 @@ bool UpdateInterface::copyStructure()
|
||||
|
||||
int cnt = 0;
|
||||
|
||||
while (itdirs.hasNext())
|
||||
processEvents();
|
||||
|
||||
while (isOkay() && itdirs.hasNext())
|
||||
{
|
||||
QFileInfo src(itdirs.next());
|
||||
|
||||
@@ -323,6 +341,7 @@ bool UpdateInterface::copyStructure()
|
||||
|
||||
m_status->reportProgress(tr("Check/create directory: %1").arg(dir), QtDebugMsg);
|
||||
cnt++;
|
||||
processEvents();
|
||||
}
|
||||
|
||||
m_status->reportProgress(tr("Directories checked/created: %1").arg(cnt), QtInfoMsg);
|
||||
@@ -334,9 +353,11 @@ bool UpdateInterface::copyStructure()
|
||||
|
||||
cnt = 0;
|
||||
|
||||
processEvents();
|
||||
|
||||
//m_status->reportProgress(tr("Calculating number of files"), QtDebugMsg);
|
||||
|
||||
while (itcnt.hasNext())
|
||||
while (isOkay() && itcnt.hasNext())
|
||||
{
|
||||
QFileInfo src(itcnt.next());
|
||||
|
||||
@@ -352,7 +373,9 @@ bool UpdateInterface::copyStructure()
|
||||
|
||||
cnt = 0;
|
||||
|
||||
while (itfiles.hasNext())
|
||||
processEvents();
|
||||
|
||||
while (isOkay() && itfiles.hasNext())
|
||||
{
|
||||
QFileInfo src(itfiles.next());
|
||||
|
||||
@@ -379,20 +402,24 @@ bool UpdateInterface::copyStructure()
|
||||
m_status->reportProgress(tr("Copied %1 to %2").arg(src.fileName()).arg(dest.fileName()), QtDebugMsg);
|
||||
cnt++;
|
||||
m_status->setValue(cnt);
|
||||
processEvents();
|
||||
}
|
||||
|
||||
m_status->setValue(m_status->maximum());
|
||||
m_status->reportProgress(tr("Files copied: %1").arg(cnt), QtInfoMsg);
|
||||
|
||||
if (!isOkay())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int UpdateInterface::copyToDestination()
|
||||
{
|
||||
m_status->progressMessage(tr("Copying to destination"));
|
||||
m_status->progressMessage(tr("Copying files to destination"));
|
||||
|
||||
if (!copyFlaggedAssets()) {
|
||||
m_status->reportProgress(tr("Unable to copy assets"), QtDebugMsg);
|
||||
m_status->reportProgress(tr("Unable to copy files"), QtDebugMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -401,10 +428,10 @@ int UpdateInterface::copyToDestination()
|
||||
|
||||
int UpdateInterface::decompress()
|
||||
{
|
||||
m_status->progressMessage(tr("Decompressing assets"));
|
||||
m_status->progressMessage(tr("Decompressing files"));
|
||||
|
||||
if (!decompressFlaggedAssets()) {
|
||||
m_status->reportProgress(tr("Unable to decompress flagged assets"), QtDebugMsg);
|
||||
m_status->reportProgress(tr("Unable to decompress flagged files"), QtDebugMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -418,11 +445,16 @@ const QString UpdateInterface::decompressDir() const
|
||||
|
||||
bool UpdateInterface::decompressFlaggedAssets()
|
||||
{
|
||||
if (!isOkay())
|
||||
return true;
|
||||
|
||||
m_repo->assets()->setFilterFlags(UPDFLG_Decompress);
|
||||
m_status->reportProgress(tr("Asset filter applied: %1 - %2 found").arg(updateFlagToString(UPDFLG_Decompress)).arg(m_repo->assets()->count()), QtDebugMsg);
|
||||
|
||||
for (int i = 0; i < m_repo->assets()->count(); ++i) {
|
||||
if (!decompressAsset(i))
|
||||
if (!isOkay())
|
||||
return true;
|
||||
else if (!decompressAsset(i))
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -454,6 +486,8 @@ bool UpdateInterface::decompressAsset(int row)
|
||||
|
||||
bool UpdateInterface::decompressArchive(const QString & archivePath, const QString & destDir)
|
||||
{
|
||||
bool ret = true;
|
||||
|
||||
QString dest = destDir;
|
||||
|
||||
if (!dest.endsWith("/"))
|
||||
@@ -463,12 +497,16 @@ bool UpdateInterface::decompressArchive(const QString & archivePath, const QStri
|
||||
|
||||
MinizInterface mIface(m_status->progress(), MinizInterface::PCM_SIZE, m_params->logLevel);
|
||||
|
||||
connect(this, &UpdateInterface::stopping, &mIface, &MinizInterface::stop, Qt::DirectConnection);
|
||||
|
||||
if (!mIface.unzipArchiveToPath(archivePath, dest)) {
|
||||
m_status->reportProgress(tr("Failed to decompress %1").arg(archivePath), QtCriticalMsg);
|
||||
return false;
|
||||
ret = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
disconnect(this, &UpdateInterface::stopping, &mIface, &MinizInterface::stop);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const QString UpdateInterface::downloadDir() const
|
||||
@@ -478,11 +516,16 @@ const QString UpdateInterface::downloadDir() const
|
||||
|
||||
bool UpdateInterface::downloadFlaggedAssets()
|
||||
{
|
||||
if (!isOkay())
|
||||
return true;
|
||||
|
||||
m_repo->assets()->setFilterFlags(UPDFLG_Download);
|
||||
m_status->reportProgress(tr("Asset filter applied: %1 - %2 found").arg(updateFlagToString(UPDFLG_Download)).arg(m_repo->assets()->count()), QtDebugMsg);
|
||||
|
||||
for (int i = 0; i < m_repo->assets()->count(); ++i) {
|
||||
if (!downloadFlaggedAsset(i))
|
||||
if (!isOkay())
|
||||
return true;
|
||||
else if (!downloadFlaggedAsset(i))
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -499,7 +542,7 @@ int UpdateInterface::download()
|
||||
m_status->progressMessage(tr("Downloading..."));
|
||||
|
||||
if (!downloadFlaggedAssets()) {
|
||||
m_status->reportProgress(tr("Unable to download flagged assets"), QtDebugMsg);
|
||||
m_status->reportProgress(tr("Unable to download flagged files"), QtDebugMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -540,6 +583,9 @@ bool UpdateInterface::flagAssets()
|
||||
|
||||
int UpdateInterface::housekeeping()
|
||||
{
|
||||
if (!isOkay())
|
||||
return PROC_RESULT_CANCELLED;
|
||||
|
||||
m_status->progressMessage(tr("Housekeeping"));
|
||||
int cnt = 0;
|
||||
|
||||
@@ -667,10 +713,16 @@ UpdateNetwork* const UpdateInterface::network() const
|
||||
|
||||
void UpdateInterface::onStatusCancelled()
|
||||
{
|
||||
m_status->setMaximum(0);
|
||||
m_result = PROC_RESULT_CANCELLED;
|
||||
m_stopping = true;
|
||||
emit stop();
|
||||
m_status->reportProgress(tr("Update cancelled"), QtWarningMsg);
|
||||
m_status->setValue(100);
|
||||
m_status->reportProgress(tr("Update cancelled by user"), QtWarningMsg);
|
||||
emit stopping();
|
||||
|
||||
if (m_eventLoop.isRunning()) {
|
||||
m_eventLoop.processEvents();
|
||||
m_eventLoop.quit();
|
||||
}
|
||||
}
|
||||
|
||||
UpdateParameters* const UpdateInterface::params() const
|
||||
@@ -709,6 +761,10 @@ int UpdateInterface::preparation()
|
||||
if (!m_repo->assets()->retrieveMetaDataAll())
|
||||
return false;
|
||||
|
||||
// clear filters from previous runs
|
||||
if (!m_repo->assets()->resetFlags())
|
||||
return false;
|
||||
|
||||
m_status->setValue(++cnt);
|
||||
|
||||
if (!flagAssets())
|
||||
@@ -719,6 +775,11 @@ int UpdateInterface::preparation()
|
||||
return true;
|
||||
}
|
||||
|
||||
void UpdateInterface::processEvents()
|
||||
{
|
||||
m_eventLoop.processEvents();
|
||||
}
|
||||
|
||||
void UpdateInterface::radioProfileChanged()
|
||||
{
|
||||
resetEnvironment();
|
||||
@@ -809,57 +870,73 @@ bool UpdateInterface::retrieveRepoJsonFile(const QString & filename, QJsonDocume
|
||||
|
||||
void UpdateInterface::runAsyncInstall()
|
||||
{
|
||||
m_status->setValue(0);
|
||||
m_result = asyncInstall();
|
||||
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 start async failed").arg(m_name), QtCriticalMsg);
|
||||
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 start async %2").arg(m_name).arg(resultToString()), QtCriticalMsg);
|
||||
m_status->setValue(m_status->maximum());
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void UpdateInterface::runBuild()
|
||||
{
|
||||
m_status->setValue(0);
|
||||
m_result = build();
|
||||
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 preparation failed").arg(m_name), QtCriticalMsg);
|
||||
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 preparation %2").arg(m_name).arg(resultToString()), QtCriticalMsg);
|
||||
m_status->setValue(m_status->maximum());
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void UpdateInterface::runCopyToDestination()
|
||||
{
|
||||
m_status->setValue(0);
|
||||
m_result = copyToDestination();
|
||||
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 copy to destination failed").arg(m_name), QtCriticalMsg);
|
||||
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 copy to destination %2").arg(m_name).arg(resultToString()), QtCriticalMsg);
|
||||
m_status->setValue(m_status->maximum());
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void UpdateInterface::runDecompress()
|
||||
{
|
||||
m_status->setValue(0);
|
||||
m_result = decompress();
|
||||
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 decompress failed").arg(m_name), QtCriticalMsg);
|
||||
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 decompress %2").arg(m_name).arg(resultToString()), QtCriticalMsg);
|
||||
m_status->setValue(m_status->maximum());
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void UpdateInterface::runDownload()
|
||||
{
|
||||
m_status->setValue(0);
|
||||
m_result = download();
|
||||
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 download failed").arg(m_name), QtCriticalMsg);
|
||||
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 download %2").arg(m_name).arg(resultToString()), QtCriticalMsg);
|
||||
m_status->setValue(m_status->maximum());
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void UpdateInterface::runHousekeeping()
|
||||
{
|
||||
m_status->setValue(0);
|
||||
m_result = housekeeping();
|
||||
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 housekeeping failed").arg(m_name), QtCriticalMsg);
|
||||
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 housekeeping %2").arg(m_name).arg(resultToString()), QtCriticalMsg);
|
||||
m_status->setValue(m_status->maximum());
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void UpdateInterface::runPreparation()
|
||||
{
|
||||
m_status->setValue(0);
|
||||
m_result = preparation();
|
||||
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 preparation failed").arg(m_name), QtCriticalMsg);
|
||||
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 preparation %2").arg(m_name).arg(resultToString()), QtCriticalMsg);
|
||||
m_status->setValue(m_status->maximum());
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void UpdateInterface::runReleaseSettingsSave()
|
||||
{
|
||||
m_status->setValue(0);
|
||||
m_result = releaseSettingsSave();
|
||||
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 save release settings failed").arg(m_name), QtCriticalMsg);
|
||||
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 save release settings %2").arg(m_name).arg(resultToString()), QtCriticalMsg);
|
||||
m_status->setValue(m_status->maximum());
|
||||
emit finished();
|
||||
}
|
||||
|
||||
@@ -1021,72 +1098,92 @@ bool UpdateInterface::update(ProgressWidget * progress)
|
||||
// and then display close button
|
||||
status()->keepOpen(true);
|
||||
|
||||
// handle Cancel button pressed
|
||||
connect(m_status, &UpdateStatus::cancelled, this, &UpdateInterface::onStatusCancelled);
|
||||
|
||||
// need to create a separate thread for the processes so that the cancel request can be handled asap
|
||||
QEventLoop loop;
|
||||
//=====================================================================================================
|
||||
// EXTREMELY IMPORTANT !!!!!!
|
||||
//
|
||||
// Every process within the event loop MUST emit finished() otherwise the event loop will not exit
|
||||
//=====================================================================================================
|
||||
connect(this, &UpdateInterface::finished, [&]() {
|
||||
if (m_eventLoop.isRunning())
|
||||
m_eventLoop.quit();
|
||||
});
|
||||
|
||||
// EXTREMELY IMPORTANT: every process within the event loop MUST emit finished() otherwise the loop will not exit
|
||||
// Note: finished does not indicate the exit status
|
||||
connect(this, &UpdateInterface::finished, [&]() { if (loop.isRunning()) loop.quit(); });
|
||||
|
||||
if (okToRun()) {
|
||||
// sub-processes should also perform this test to return as early as possible on receiving cancel request
|
||||
if (isOkay()) {
|
||||
// pause before starting next process to allow time for queued events to be processed ie like the cancel request
|
||||
QTimer::singleShot(100, this, &UpdateInterface::runPreparation);
|
||||
// NOTE: this will not exit until the finished signal is detected and processed
|
||||
loop.exec();
|
||||
QTimer::singleShot(500, this, &UpdateInterface::runPreparation);
|
||||
// NOTE: this will not exit until the finished or cancelled signal is detected and processed
|
||||
m_eventLoop.exec();
|
||||
}
|
||||
|
||||
if (okToRun()) {
|
||||
QTimer::singleShot(100, this, &UpdateInterface::runBuild);
|
||||
loop.exec();
|
||||
if (isOkay()) {
|
||||
QTimer::singleShot(500, this, &UpdateInterface::runBuild);
|
||||
m_eventLoop.exec();
|
||||
}
|
||||
|
||||
if (okToRun()) {
|
||||
QTimer::singleShot(100, this, &UpdateInterface::runDownload);
|
||||
loop.exec();
|
||||
if (isOkay()) {
|
||||
QTimer::singleShot(500, this, &UpdateInterface::runDownload);
|
||||
m_eventLoop.exec();
|
||||
}
|
||||
|
||||
if (okToRun()) {
|
||||
QTimer::singleShot(100, this, &UpdateInterface::runDecompress);
|
||||
loop.exec();
|
||||
if (isOkay()) {
|
||||
QTimer::singleShot(500, this, &UpdateInterface::runDecompress);
|
||||
m_eventLoop.exec();
|
||||
}
|
||||
|
||||
if (okToRun()) {
|
||||
QTimer::singleShot(100, this, &UpdateInterface::runCopyToDestination);
|
||||
loop.exec();
|
||||
if (isOkay()) {
|
||||
QTimer::singleShot(500, this, &UpdateInterface::runCopyToDestination);
|
||||
m_eventLoop.exec();
|
||||
}
|
||||
|
||||
// perform before async install in case Companion restarted
|
||||
if (okToRun()) {
|
||||
QTimer::singleShot(100, this, &UpdateInterface::runReleaseSettingsSave);
|
||||
loop.exec();
|
||||
if (isOkay()) {
|
||||
QTimer::singleShot(500, this, &UpdateInterface::runReleaseSettingsSave);
|
||||
m_eventLoop.exec();
|
||||
}
|
||||
|
||||
if (okToRun()) {
|
||||
QTimer::singleShot(100, this, &UpdateInterface::runAsyncInstall);
|
||||
loop.exec();
|
||||
if (isOkay()) {
|
||||
QTimer::singleShot(500, this, &UpdateInterface::runAsyncInstall);
|
||||
m_eventLoop.exec();
|
||||
}
|
||||
|
||||
if (okToRun()) {
|
||||
QTimer::singleShot(100, this, &UpdateInterface::runHousekeeping);
|
||||
loop.exec();
|
||||
if (isOkay()) {
|
||||
QTimer::singleShot(500, this, &UpdateInterface::runHousekeeping);
|
||||
m_eventLoop.exec();
|
||||
}
|
||||
|
||||
// remove event check from stack otherwise repeated running of update will add unnecessary duplicates
|
||||
disconnect(m_status, &UpdateStatus::cancelled, this, &UpdateInterface::onStatusCancelled);
|
||||
|
||||
m_status->reportProgress(tr("%1 update %2").arg(m_name).arg(resultToString()), QtInfoMsg);
|
||||
|
||||
if (!m_status->progress())
|
||||
QMessageBox::information(m_status->progress(), CPN_STR_APP_NAME, tr("%1 update %2").arg(m_name).arg(resultToString()));
|
||||
|
||||
// allow the dialog to be closed by clicking the close button
|
||||
status()->keepOpen(false);
|
||||
|
||||
if (!okToRun())
|
||||
return false;
|
||||
if (m_result != PROC_RESULT_SUCCESS)
|
||||
m_status->setValue(m_status->maximum());
|
||||
|
||||
m_status->reportProgress(tr("%1 update successful").arg(m_name), QtInfoMsg);
|
||||
return m_result == PROC_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
if (!m_status->progress())
|
||||
QMessageBox::information(m_status->progress(), CPN_STR_APP_NAME, tr("%1 update successful").arg(m_name));
|
||||
|
||||
return true;
|
||||
const QString UpdateInterface::resultToString() const
|
||||
{
|
||||
switch (m_result) {
|
||||
case PROC_RESULT_FAIL:
|
||||
return tr("failed");
|
||||
case PROC_RESULT_SUCCESS:
|
||||
return tr("successful");
|
||||
case PROC_RESULT_CANCELLED:
|
||||
return tr("cancelled");
|
||||
default:
|
||||
return tr("unknown");
|
||||
}
|
||||
}
|
||||
|
||||
const QString UpdateInterface::updateDir() const
|
||||
|
||||
@@ -107,7 +107,7 @@ class UpdateInterface : public QWidget
|
||||
bool update(ProgressWidget * progress = nullptr);
|
||||
|
||||
signals:
|
||||
void stop();
|
||||
void stopping();
|
||||
void finished();
|
||||
|
||||
protected:
|
||||
@@ -156,6 +156,7 @@ class UpdateInterface : public QWidget
|
||||
|
||||
private slots:
|
||||
void onStatusCancelled();
|
||||
void processEvents();
|
||||
|
||||
private:
|
||||
const ComponentIdentity m_id;
|
||||
@@ -169,6 +170,8 @@ class UpdateInterface : public QWidget
|
||||
QString m_updateDir;
|
||||
bool m_stopping;
|
||||
int m_result;
|
||||
QEventLoop m_eventLoop;
|
||||
QTimer m_timer;
|
||||
|
||||
void appSettingsInit();
|
||||
bool checkCreateDirectory(const QString & dirSetting, const UpdateFlags flag);
|
||||
@@ -177,7 +180,9 @@ class UpdateInterface : public QWidget
|
||||
bool setRunFolders();
|
||||
bool validateFolder(QString & fldr);
|
||||
|
||||
bool okToRun() { return m_result == PROC_RESULT_SUCCESS && m_stopping == false; }
|
||||
bool isOkay() { return m_result == PROC_RESULT_SUCCESS && !m_stopping; }
|
||||
const QString resultToString() const;
|
||||
|
||||
void runAsyncInstall();
|
||||
void runBuild();
|
||||
void runCopyToDestination();
|
||||
|
||||
@@ -49,6 +49,30 @@ UpdateNetwork::~UpdateNetwork()
|
||||
delete m_file;
|
||||
}
|
||||
|
||||
void UpdateNetwork::cleanup()
|
||||
{
|
||||
if (m_timer.isActive())
|
||||
m_timer.stop();
|
||||
|
||||
disconnect(&m_timer, &QTimer::timeout, this, &UpdateNetwork::updateProgress);
|
||||
|
||||
if (m_eventLoop.isRunning())
|
||||
m_eventLoop.quit();
|
||||
}
|
||||
|
||||
void UpdateNetwork::connectReplyCommon()
|
||||
{
|
||||
connect(m_reply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::errorOccurred), [=] (QNetworkReply::NetworkError code) {
|
||||
m_success = false;
|
||||
m_status->reportProgress(tr("Network error has occurred. Error code: %1").arg(code), QtCriticalMsg);
|
||||
});
|
||||
|
||||
connect(m_reply, &QNetworkReply::sslErrors, [=]() {
|
||||
m_success = false;
|
||||
m_status->reportProgress(tr("Ssl library version: %1").arg(QSslSocket::sslLibraryVersionString()), QtCriticalMsg);
|
||||
});
|
||||
}
|
||||
|
||||
void UpdateNetwork::convertBufferToJson(QJsonDocument * json)
|
||||
{
|
||||
m_success = false;
|
||||
@@ -64,6 +88,57 @@ void UpdateNetwork::convertBufferToJson(QJsonDocument * json)
|
||||
m_success = true;
|
||||
}
|
||||
|
||||
void UpdateNetwork::download(const DownloadDataType type, const QString & url, const char * acceptHeader, const QString & filePath)
|
||||
{
|
||||
m_action = tr("Downloading");
|
||||
|
||||
if (!init(url))
|
||||
return;
|
||||
|
||||
if (type == DDT_GitHub_SaveToFile || type == DDT_Build_SaveToFile) {
|
||||
m_file = new QFile(filePath);
|
||||
if (!m_file->open(QIODevice::WriteOnly)) {
|
||||
m_status->reportProgress(tr("Unable to open the download file %1 for writing. Error: %2").arg(filePath).arg(m_file->errorString()), QtCriticalMsg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_file = nullptr;
|
||||
|
||||
if (type >= DDT_GitHub_First && type <= DDT_GitHub_Last) {
|
||||
m_request.setRawHeader(QByteArray("X-GitHub-Api-Version"), GH_API_VERSION);
|
||||
m_request.setRawHeader(QByteArray("Accept"), QByteArray(acceptHeader));
|
||||
}
|
||||
|
||||
// returns a new QNetworkReply object
|
||||
m_reply = m_manager.get(m_request);
|
||||
|
||||
// connect to the signals of the new object
|
||||
connectReplyCommon();
|
||||
|
||||
connect(m_reply, &QNetworkReply::downloadProgress, [=](const qint64 bytesRead, const qint64 totalBytes) {
|
||||
m_status->setMaximum(totalBytes);
|
||||
m_status->setValue(bytesRead);
|
||||
});
|
||||
|
||||
connect(m_reply, &QNetworkReply::readyRead, [=]() {
|
||||
if (type == DDT_GitHub_SaveToFile || type == DDT_Build_SaveToFile) {
|
||||
m_file->write(m_reply->readAll());
|
||||
}
|
||||
else {
|
||||
const QByteArray qba = m_reply->readAll();
|
||||
m_buffer->append(qba);
|
||||
}
|
||||
});
|
||||
|
||||
connect(m_reply, &QNetworkReply::finished, [=]() { onGetFinished(m_reply, type); });
|
||||
|
||||
connect(m_status, &UpdateStatus::cancelled, this, &UpdateNetwork::cancelDownload);
|
||||
|
||||
m_timer.start();
|
||||
m_eventLoop.exec();
|
||||
}
|
||||
|
||||
// static
|
||||
QString UpdateNetwork::downloadDataTypeToString(const DownloadDataType val)
|
||||
{
|
||||
@@ -140,6 +215,7 @@ void UpdateNetwork::downloadToFile(const DownloadDataType type, const QString &
|
||||
int reply = QMessageBox::question(m_status->progress(), CPN_STR_APP_NAME, tr("File %1 exists. Download again?").arg(fi.fileName()),
|
||||
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::No);
|
||||
if (reply == QMessageBox::Cancel) {
|
||||
m_status->reportProgress(tr("Download cancelled by user"), QtWarningMsg);
|
||||
return;
|
||||
}
|
||||
else if (reply == QMessageBox::No) {
|
||||
@@ -162,82 +238,6 @@ void UpdateNetwork::downloadToFile(const DownloadDataType type, const QString &
|
||||
fi.absoluteFilePath());
|
||||
}
|
||||
|
||||
void UpdateNetwork::download(const DownloadDataType type, const QString & url, const char * acceptHeader, const QString & filePath)
|
||||
{
|
||||
m_status->setValue(0);
|
||||
m_status->setMaximum(100);
|
||||
|
||||
if (!init(url))
|
||||
return;
|
||||
|
||||
if (type == DDT_GitHub_SaveToFile || type == DDT_Build_SaveToFile) {
|
||||
m_file = new QFile(filePath);
|
||||
if (!m_file->open(QIODevice::WriteOnly)) {
|
||||
m_status->reportProgress(tr("Unable to open the download file %1 for writing. Error: %2").arg(filePath).arg(m_file->errorString()), QtCriticalMsg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_file = nullptr;
|
||||
|
||||
if (type >= DDT_GitHub_First && type <= DDT_GitHub_Last) {
|
||||
m_request.setRawHeader(QByteArray("X-GitHub-Api-Version"), GH_API_VERSION);
|
||||
m_request.setRawHeader(QByteArray("Accept"), QByteArray(acceptHeader));
|
||||
}
|
||||
|
||||
// run GET inside event loop with timer interrupts to allow other events to run
|
||||
QEventLoop loop;
|
||||
|
||||
QTimer timer;
|
||||
timer.setInterval(1000);
|
||||
|
||||
connect(&timer, &QTimer::timeout, [&]() {
|
||||
m_status->reportProgress(tr("Downloading..."), QtDebugMsg);
|
||||
});
|
||||
|
||||
m_reply = m_manager.get(m_request);
|
||||
|
||||
connect(m_reply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::errorOccurred), [=] (QNetworkReply::NetworkError code) {
|
||||
m_success = false;
|
||||
m_status->reportProgress(tr("Network error has occurred. Error code: %1").arg(code), QtCriticalMsg);
|
||||
});
|
||||
|
||||
connect(m_reply, &QNetworkReply::sslErrors, [=]() {
|
||||
m_success = false;
|
||||
m_status->reportProgress(tr("Ssl library version: %1").arg(QSslSocket::sslLibraryVersionString()), QtCriticalMsg);
|
||||
});
|
||||
|
||||
connect(m_reply, &QNetworkReply::downloadProgress, [=](const qint64 bytesRead, const qint64 totalBytes) {
|
||||
m_status->setMaximum(totalBytes);
|
||||
m_status->setValue(bytesRead);
|
||||
});
|
||||
|
||||
connect(m_reply, &QNetworkReply::readyRead, [=]() {
|
||||
if (type == DDT_GitHub_SaveToFile || type == DDT_Build_SaveToFile) {
|
||||
m_file->write(m_reply->readAll());
|
||||
}
|
||||
else {
|
||||
const QByteArray qba = m_reply->readAll();
|
||||
m_buffer->append(qba);
|
||||
}
|
||||
});
|
||||
|
||||
connect(m_reply, &QNetworkReply::finished, [&]() {
|
||||
if (timer.isActive())
|
||||
timer.stop();
|
||||
|
||||
if (loop.isRunning())
|
||||
loop.quit();
|
||||
|
||||
disconnect(m_reply, nullptr);
|
||||
|
||||
onDownloadFinished(m_reply, type);
|
||||
});
|
||||
|
||||
timer.start();
|
||||
loop.exec();
|
||||
}
|
||||
|
||||
QByteArray * UpdateNetwork::getDownloadBuffer()
|
||||
{
|
||||
return m_buffer;
|
||||
@@ -245,10 +245,21 @@ QByteArray * UpdateNetwork::getDownloadBuffer()
|
||||
|
||||
bool UpdateNetwork::init(const QString & urlStr)
|
||||
{
|
||||
m_status->setValue(0);
|
||||
m_status->setMaximum(100);
|
||||
|
||||
m_buffer->clear();
|
||||
m_success = false;
|
||||
m_request = QNetworkRequest();
|
||||
|
||||
if (m_reply) {
|
||||
delete m_reply;
|
||||
m_reply = nullptr;
|
||||
}
|
||||
|
||||
m_timer.setInterval(1000);
|
||||
connect(&m_timer, &QTimer::timeout, this, &UpdateNetwork::updateProgress);
|
||||
|
||||
m_url.setUrl(urlStr);
|
||||
|
||||
if (!m_url.isValid()) {
|
||||
@@ -269,8 +280,11 @@ const bool UpdateNetwork::isSuccess()
|
||||
return m_success;
|
||||
}
|
||||
|
||||
void UpdateNetwork::onDownloadFinished(QNetworkReply * reply, DownloadDataType type)
|
||||
void UpdateNetwork::onGetFinished(QNetworkReply * reply, DownloadDataType type)
|
||||
{
|
||||
cleanup();
|
||||
disconnect(m_status, &UpdateStatus::cancelled, this, &UpdateNetwork::cancelDownload);
|
||||
|
||||
m_status->setValue(m_status->maximum());
|
||||
|
||||
if (type == DDT_GitHub_SaveToFile || type == DDT_Build_SaveToFile) {
|
||||
@@ -292,64 +306,56 @@ void UpdateNetwork::onDownloadFinished(QNetworkReply * reply, DownloadDataType t
|
||||
delete m_file;
|
||||
m_file = nullptr;
|
||||
}
|
||||
|
||||
if (m_reply) {
|
||||
delete m_reply;
|
||||
m_reply = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateNetwork::onPostFinished()
|
||||
{
|
||||
cleanup();
|
||||
|
||||
if (m_reply->error()) {
|
||||
m_success = false;
|
||||
m_status->reportProgress(tr("POST error: %2\n%3").arg(m_reply->error()).arg(m_reply->errorString()), QtCriticalMsg);
|
||||
}
|
||||
|
||||
if (m_reply) {
|
||||
delete m_reply;
|
||||
m_reply = nullptr;
|
||||
}
|
||||
|
||||
m_success = true;
|
||||
}
|
||||
|
||||
void UpdateNetwork::post(const QString & action, const QString & url, QJsonDocument * data)
|
||||
{
|
||||
m_status->setValue(0);
|
||||
m_status->setMaximum(0); // put progress bar in wait mode
|
||||
m_action = action;
|
||||
|
||||
if (!init(url))
|
||||
return;
|
||||
|
||||
m_status->setMaximum(0); // put progress bar into wait mode as cannot guess how long request will run
|
||||
|
||||
m_request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
|
||||
// run POST inside event loop with timer interrupts to allow other events to run
|
||||
QEventLoop loop;
|
||||
|
||||
QTimer timer;
|
||||
timer.setInterval(1000);
|
||||
|
||||
connect(&timer, &QTimer::timeout, [&]() {
|
||||
m_status->reportProgress(QString("%1...").arg(action), QtDebugMsg);
|
||||
});
|
||||
|
||||
// returns a new QNetworkReply object
|
||||
m_reply = m_manager.post(m_request, data->toJson(QJsonDocument::Compact));
|
||||
|
||||
connect(m_reply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::errorOccurred), [=] (QNetworkReply::NetworkError code) {
|
||||
m_success = false;
|
||||
m_status->reportProgress(tr("Network error has occurred. Error code: %1").arg(code), QtCriticalMsg);
|
||||
});
|
||||
|
||||
connect(m_reply, &QNetworkReply::sslErrors, [=]() {
|
||||
m_success = false;
|
||||
m_status->reportProgress(tr("Ssl library version: %1").arg(QSslSocket::sslLibraryVersionString()), QtCriticalMsg);
|
||||
});
|
||||
// connect to the signals of the new object
|
||||
connectReplyCommon();
|
||||
|
||||
connect(m_reply, &QNetworkReply::readyRead, [=]() {
|
||||
const QByteArray qba = m_reply->readAll();
|
||||
m_buffer->append(qba);
|
||||
});
|
||||
|
||||
connect(m_reply, &QNetworkReply::finished, [&]() {
|
||||
if (timer.isActive())
|
||||
timer.stop();
|
||||
connect(m_reply, &QNetworkReply::finished, this, &UpdateNetwork::onPostFinished);
|
||||
|
||||
if (loop.isRunning())
|
||||
loop.quit();
|
||||
|
||||
disconnect(m_reply, nullptr);
|
||||
|
||||
if (m_reply->error()) {
|
||||
m_success = false;
|
||||
m_status->reportProgress(tr("POST error: %2\n%3").arg(m_reply->error()).arg(m_reply->errorString()), QtCriticalMsg);
|
||||
}
|
||||
|
||||
m_success = true;
|
||||
});
|
||||
|
||||
timer.start();
|
||||
loop.exec();
|
||||
m_timer.start();
|
||||
m_eventLoop.exec();
|
||||
}
|
||||
|
||||
bool UpdateNetwork::saveBufferToFile(const QString & filePath)
|
||||
@@ -396,3 +402,14 @@ void UpdateNetwork::submitRequest(const QString & action, const QString & url, Q
|
||||
if (m_success)
|
||||
convertBufferToJson(response);
|
||||
}
|
||||
|
||||
void UpdateNetwork::cancelDownload()
|
||||
{
|
||||
m_status->reportProgress(tr("Download cancelled"), QtWarningMsg);
|
||||
m_reply->abort();
|
||||
}
|
||||
|
||||
void UpdateNetwork::updateProgress()
|
||||
{
|
||||
m_status->reportProgress(QString("%1...").arg(m_action), QtDebugMsg);
|
||||
}
|
||||
|
||||
@@ -72,7 +72,10 @@ class UpdateNetwork : public QObject
|
||||
static QString downloadDataTypeToString(const DownloadDataType val);
|
||||
|
||||
private slots:
|
||||
void onDownloadFinished(QNetworkReply * reply, DownloadDataType ddt);
|
||||
void onGetFinished(QNetworkReply * reply, DownloadDataType ddt);
|
||||
void onPostFinished();
|
||||
void updateProgress();
|
||||
void cancelDownload();
|
||||
|
||||
private:
|
||||
UpdateStatus *m_status;
|
||||
@@ -83,6 +86,11 @@ class UpdateNetwork : public QObject
|
||||
QFile *m_file;
|
||||
QUrl m_url;
|
||||
bool m_success;
|
||||
QEventLoop m_eventLoop;
|
||||
QTimer m_timer;
|
||||
QString m_action;
|
||||
|
||||
bool init(const QString & url);
|
||||
void connectReplyCommon();
|
||||
void cleanup();
|
||||
};
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "helpers.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QApplication>
|
||||
|
||||
Updates::Updates(QWidget * parent, UpdateFactories * updateFactories) :
|
||||
QWidget(parent),
|
||||
@@ -127,6 +128,9 @@ void Updates::runUpdate()
|
||||
ok = factories->updateAll(progressDialog.progress());
|
||||
progressDialog.setProcessStopped();
|
||||
progressDialog.progress()->setInfo(tr("Finished %1").arg(ok ? tr("successfully") : tr("with errors")));
|
||||
progressDialog.progress()->setValue(progressDialog.progress()->maximum());
|
||||
progressDialog.progress()->refresh();
|
||||
QApplication::processEvents();
|
||||
progressDialog.exec();
|
||||
|
||||
if (ok)
|
||||
|
||||
Reference in New Issue
Block a user