cutter/src/common/UpdateWorker.cpp

221 lines
8.3 KiB
C++
Raw Normal View History

#include "UpdateWorker.h"
#if CUTTER_UPDATE_WORKER_AVAILABLE
2021-01-24 14:50:13 +00:00
# include <QUrl>
# include <QFile>
# include <QTimer>
# include <QEventLoop>
# include <QDataStream>
# include <QJsonObject>
# include <QApplication>
# include <QJsonDocument>
# include <QDesktopServices>
# include <QtNetwork/QNetworkReply>
# include <QtNetwork/QNetworkRequest>
# include <QStandardPaths>
2021-01-24 14:50:13 +00:00
# include <QProgressDialog>
# include <QPushButton>
# include <QFileDialog>
# include <QMessageBox>
# include "common/Configuration.h"
# include "CutterConfig.h"
#endif
#if CUTTER_UPDATE_WORKER_AVAILABLE
2021-01-24 14:50:13 +00:00
UpdateWorker::UpdateWorker(QObject *parent) : QObject(parent), pending(false)
{
connect(&t, &QTimer::timeout, this, [this]() {
if (pending) {
disconnect(checkReply, nullptr, this, nullptr);
checkReply->close();
checkReply->deleteLater();
2021-01-24 14:50:13 +00:00
emit checkComplete(QVersionNumber(),
tr("Time limit exceeded during version check. Please check your "
"internet connection and try again."));
}
});
}
void UpdateWorker::checkCurrentVersion(time_t timeoutMs)
{
QUrl url("https://api.github.com/repos/rizinorg/cutter/releases/latest");
QNetworkRequest request;
request.setUrl(url);
t.setInterval(timeoutMs);
t.setSingleShot(true);
t.start();
checkReply = nm.get(request);
2021-01-24 14:50:13 +00:00
connect(checkReply, &QNetworkReply::finished, this, &UpdateWorker::serveVersionCheckReply);
pending = true;
}
void UpdateWorker::download(QString filename, QString version)
{
downloadFile.setFileName(filename);
downloadFile.open(QIODevice::WriteOnly);
QNetworkRequest request;
# if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) && QT_VERSION < QT_VERSION_CHECK(5, 9, 0)
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
# elif QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute,
QNetworkRequest::RedirectPolicy::NoLessSafeRedirectPolicy);
# endif
QUrl url(QString("https://github.com/rizinorg/cutter/releases/"
2021-01-24 14:50:13 +00:00
"download/v%1/%2")
.arg(version)
.arg(getRepositoryFileName()));
request.setUrl(url);
downloadReply = nm.get(request);
2021-01-24 14:50:13 +00:00
connect(downloadReply, &QNetworkReply::downloadProgress, this, &UpdateWorker::process);
connect(downloadReply, &QNetworkReply::finished, this, &UpdateWorker::serveDownloadFinish);
}
void UpdateWorker::showUpdateDialog(bool showDontCheckForUpdatesButton)
{
QMessageBox mb;
mb.setWindowTitle(tr("Version control"));
2021-01-24 14:50:13 +00:00
mb.setText(tr("There is an update available for Cutter.<br/>") + "<b>" + tr("Current version:")
+ "</b> " CUTTER_VERSION_FULL "<br/>" + "<b>" + tr("Latest version:") + "</b> "
+ latestVersion.toString() + "<br/><br/>"
+ tr("For update, please check the link:<br/>")
+ QString("<a href=\"https://github.com/rizinorg/cutter/releases/tag/v%1\">"
2021-01-24 14:50:13 +00:00
"https://github.com/rizinorg/cutter/releases/tag/v%1</a><br/>")
.arg(latestVersion.toString())
+ tr("or click \"Download\" to download latest version of Cutter."));
if (showDontCheckForUpdatesButton) {
mb.setStandardButtons(QMessageBox::Save | QMessageBox::Reset | QMessageBox::Ok);
mb.button(QMessageBox::Reset)->setText(tr("Don't check for updates"));
} else {
mb.setStandardButtons(QMessageBox::Save | QMessageBox::Ok);
}
mb.button(QMessageBox::Save)->setText(tr("Download"));
mb.setDefaultButton(QMessageBox::Ok);
int ret = mb.exec();
if (ret == QMessageBox::Reset) {
Config()->setAutoUpdateEnabled(false);
} else if (ret == QMessageBox::Save) {
2021-01-24 14:50:13 +00:00
QString fullFileName = QFileDialog::getSaveFileName(
nullptr, tr("Choose directory for downloading"),
QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + QDir::separator()
+ getRepositoryFileName(),
QString("%1 (*.%1)").arg(getRepositeryExt()));
2019-03-23 10:54:34 +00:00
if (!fullFileName.isEmpty()) {
2021-01-24 14:50:13 +00:00
QProgressDialog progressDial(tr("Downloading update..."), tr("Cancel"), 0, 100);
connect(this, &UpdateWorker::downloadProcess, &progressDial,
[&progressDial](size_t curr, size_t total) {
2021-01-24 14:50:13 +00:00
progressDial.setValue(100.0f * curr / total);
});
connect(&progressDial, &QProgressDialog::canceled, this, &UpdateWorker::abortDownload);
connect(this, &UpdateWorker::downloadFinished, &progressDial, &QProgressDialog::cancel);
connect(this, &UpdateWorker::downloadFinished, this, [](QString filePath) {
QMessageBox info(QMessageBox::Information, tr("Download finished!"),
tr("Latest version of Cutter was succesfully downloaded!"),
2021-01-24 14:50:13 +00:00
QMessageBox::Yes | QMessageBox::Open | QMessageBox::Ok, nullptr);
info.button(QMessageBox::Open)->setText(tr("Open file"));
info.button(QMessageBox::Yes)->setText(tr("Open download folder"));
int r = info.exec();
if (r == QMessageBox::Open) {
QDesktopServices::openUrl(filePath);
} else if (r == QMessageBox::Yes) {
auto path = filePath.split('/');
path.removeLast();
QDesktopServices::openUrl(path.join('/'));
}
});
download(fullFileName, latestVersion.toString());
// Calling show() before exec() is only way make dialog non-modal
2020-01-28 08:02:17 +00:00
// it seems weird, but it works
progressDial.show();
progressDial.exec();
}
}
}
void UpdateWorker::abortDownload()
{
2021-01-24 14:50:13 +00:00
disconnect(downloadReply, &QNetworkReply::finished, this, &UpdateWorker::serveDownloadFinish);
disconnect(downloadReply, &QNetworkReply::downloadProgress, this, &UpdateWorker::process);
downloadReply->close();
downloadReply->deleteLater();
downloadFile.remove();
}
void UpdateWorker::serveVersionCheckReply()
{
pending = false;
QString versionReplyStr = "";
QString errStr = "";
if (checkReply->error()) {
errStr = checkReply->errorString();
} else {
2021-01-24 14:50:13 +00:00
versionReplyStr = QJsonDocument::fromJson(checkReply->readAll())
.object()
.value("tag_name")
.toString();
versionReplyStr.remove('v');
}
QVersionNumber versionReply = QVersionNumber::fromString(versionReplyStr);
if (!versionReply.isNull()) {
latestVersion = versionReply;
}
checkReply->close();
checkReply->deleteLater();
emit checkComplete(versionReply, errStr);
}
void UpdateWorker::serveDownloadFinish()
{
downloadReply->close();
downloadReply->deleteLater();
if (downloadReply->error()) {
emit downloadError(downloadReply->errorString());
} else {
emit downloadFinished(downloadFile.fileName());
}
}
void UpdateWorker::process(size_t bytesReceived, size_t bytesTotal)
{
downloadFile.write(downloadReply->readAll());
emit downloadProcess(bytesReceived, bytesTotal);
}
QString UpdateWorker::getRepositeryExt() const
{
2021-01-24 14:50:13 +00:00
# ifdef Q_OS_LINUX
return "AppImage";
2021-01-24 14:50:13 +00:00
# elif defined(Q_OS_WIN64) || defined(Q_OS_WIN32)
return "zip";
2021-01-24 14:50:13 +00:00
# elif defined(Q_OS_MACOS)
return "dmg";
2021-01-24 14:50:13 +00:00
# endif
}
QString UpdateWorker::getRepositoryFileName() const
{
QString downloadFileName;
2021-01-24 14:50:13 +00:00
# ifdef Q_OS_LINUX
downloadFileName = "Cutter-v%1-x%2.Linux.AppImage";
2021-01-24 14:50:13 +00:00
# elif defined(Q_OS_WIN64) || defined(Q_OS_WIN32)
downloadFileName = "Cutter-v%1-x%2.Windows.zip";
2021-01-24 14:50:13 +00:00
# elif defined(Q_OS_MACOS)
downloadFileName = "Cutter-v%1-x%2.macOS.dmg";
2021-01-24 14:50:13 +00:00
# endif
downloadFileName =
downloadFileName.arg(latestVersion.toString())
.arg(QSysInfo::buildAbi().split('-').at(2).contains("64") ? "64" : "32");
return downloadFileName;
}
QVersionNumber UpdateWorker::currentVersionNumber()
{
return QVersionNumber(CUTTER_VERSION_MAJOR, CUTTER_VERSION_MINOR, CUTTER_VERSION_PATCH);
}
#endif // CUTTER_UPDATE_WORKER_AVAILABLE