更新模块
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

393 lines
12 KiB

#include "updaterdialog.h"
#include "ui_updaterdialog.h"
#include <QDesktopServices>
#include <QJsonDocument>
#include <QJsonObject>
#include <QMessageBox>
#include <QMetaEnum>
#include <cmath>
#include <private/qzipreader_p.h>
QString CHECK_URL = "http://www.tianzd.cn:1995/TianZD/deploy/raw/branch/master/";
QString ORIGIN_URL = "http://www.tianzd.cn:1995/TianZD/deploy/raw/branch/master/";
QString PLATFORM = "windows";
QString APPVERSION = "";
QString APPNAME = "";
QString APPDATE = "0";
QString MODIFYCNT = "0";
UpdaterDialog::UpdaterDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::UpdaterDialog)
{
ui->setupUi(this);
this->setWindowTitle("Updater");
ui->btn_update->setEnabled(0);
m_startTime = 0;
m_version = APPVERSION;
ui->versionInput->setText(m_version);
ui->appNameInput->setText(APPNAME);
ui->show->setEnabled(0);
ui->label_2->setText("");
ui->label_3->setText("");
// ui->label_4->setText(APPNAME);
// ui->versionInput->setEnabled(false);
// ui->show->appendPlainText(APPNAME);
// ui->show->appendPlainText(APPVERSION);
// ui->show->appendPlainText(APPDATE);
// ui->show->appendPlainText(MODIFYCNT);
}
UpdaterDialog::~UpdaterDialog()
{
delete ui;
}
void UpdaterDialog::showStatus(const QString &s)
{
// ui->show->clear();
ui->show->appendPlainText(s);
}
void UpdaterDialog::on_btn_check_clicked()
{
APPNAME = ui->appNameInput->text();
if(QString(APPNAME) == "")
{
ui->show->appendPlainText("Please input app name");
return;
}
ui->show->clear();
ui->btn_update->setEnabled(0);
//version
m_version = ui->versionInput->text();
if(!m_pManager)
{
m_pManager = new QNetworkAccessManager(this);
connect(m_pManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(onCheckReply(QNetworkReply *)));
}
CHECK_URL = ORIGIN_URL + APPNAME + "/updates.json";
qDebug() << APPNAME << CHECK_URL;
QNetworkRequest request(CHECK_URL);
m_pManager->get(request);
}
bool UpdaterDialog::checkVersion(const QString &_localVersion, const QString &_remoteVersion)
{
//版本号分割,1.1.2分为1 1 2
QStringList _list_curr = _localVersion.split(".");
QStringList _list_lastest = _remoteVersion.split(".");
//检查是否需要更新
bool _isNotLatest = false;
//版本号为空
if(_list_curr.count() == 0)
{
m_bDownloadFullExe = true;
return true;
}
if(_list_curr.count() != _list_lastest.count())
_isNotLatest = true;
for(int i = 0; i < _list_curr.count(); ++i)
{
if(_list_curr[i].toUInt() < _list_lastest[i].toUInt())
{
_isNotLatest = true;
}
}
//版本号一致,检查日期
if(!_isNotLatest)
{
if(m_lastChangeTime.toUInt() > APPDATE.toUInt())
{
_isNotLatest = true;
}
//检查修改次数
if(m_modifyCnt != "" && m_modifyCnt != " " && MODIFYCNT != "" && MODIFYCNT != " ")
{
if(m_modifyCnt.toUInt() > MODIFYCNT.toUInt())
{
_isNotLatest = true;
}
}
}
return _isNotLatest;
}
void UpdaterDialog::onCheckReply(QNetworkReply *reply)
{
/* There was a network error */
if (reply->error() != QNetworkReply::NoError)
{
showStatus("check error");
return;
}
/* Try to create a JSON document from downloaded data */
QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
/* JSON is invalid */
if (document.isNull())
{
showStatus("reply doc is null");
return;
}
/* Get the platform information */
QJsonObject updates = document.object().value("updates").toObject();
QJsonObject platform = updates.value(PLATFORM).toObject();
/* Get update information */
m_changelog = platform.value("changelog").toString();
m_patchVersion = platform.value("patch-version").toString();
m_fullVersion = platform.value("full-version").toString();
m_lastChangeTime = platform.value("modify-time").toString();
m_modifyCnt = platform.value("modifyCnt").toString();
m_bDownloadFullExe = platform.value("download-full").toBool();
if(m_version == "" || m_version == "0") //当前版本号为空
{
m_bDownloadFullExe = true;
}
m_fileName = APPNAME + "-patch-v" + m_patchVersion + ".zip";
m_patchUrl = platform.value("patch-url").toString() + APPNAME + "/" + APPNAME + "-patch-v" + m_patchVersion + ".zip";
m_fullUrl = platform.value("full-url").toString() + APPNAME + "/" + APPNAME + "-full-v" + m_fullVersion + ".exe";
QString _remoteVersion = m_bDownloadFullExe ? m_fullVersion : m_patchVersion;
bool _isNotLatest = checkVersion(m_version, _remoteVersion);
if(_isNotLatest)
{
showStatus("======================================"
+ tr("\ncurrent version: v") + m_version
+ tr("\nmodify time: ") + APPDATE
+ tr("\nmodify cnt: ") + MODIFYCNT
+ "\n ------------------------------"
+ tr("\nlatest version: v") + _remoteVersion
+ tr("\nmodify time: ") + m_lastChangeTime
+ tr("\nmodify cnt: ") + m_modifyCnt
+ tr("\nchange log: ") + m_changelog
+ "\n======================================"
);
if(m_bDownloadFullExe)
{
showStatus("need download full exe");
m_fileName = APPNAME + "-full-v" + m_patchVersion + ".exe";
}
showStatus(tr("click update button to update"));
}
else
{
showStatus("======================================"
+ tr("\ncurrent software is up-to-date")
+ tr("\nversion : v") + _remoteVersion
+ tr("\nmodify time: ") + m_lastChangeTime
+ tr("\nmodify cnt: ") + m_modifyCnt
+ "\n======================================"
+ tr("\nno need to update")
+ tr("\nclick cancel button to quit"));
}
ui->btn_update->setEnabled(1);
}
void UpdaterDialog::calculateSizes(qint64 received, qint64 total)
{
QString totalSize;
QString receivedSize;
if (total < 1024)
totalSize = tr("%1 bytes").arg(total);
else if (total < 1048576)
totalSize = tr("%1 KB").arg(round(total / 1024));
else
totalSize = tr("%1 MB").arg((total / 1048576.0));
if (received < 1024)
receivedSize = tr("%1 bytes").arg(received);
else if (received < 1048576)
receivedSize = tr("%1 KB").arg(received / 1024);
else
receivedSize = tr("%1 MB").arg(received / 1048576.0);
ui->label_2->setText(tr("Downloading updates") + " (" + receivedSize + " " + tr("of") + " " + totalSize
+ ")");
}
/**
* Uses two time samples (from the current time and a previous sample) to
* calculate how many bytes have been downloaded.
*
* Then, this function proceeds to calculate the appropiate units of time
* (hours, minutes or seconds) and constructs a user-friendly string, which
* is displayed in the dialog.
*/
void UpdaterDialog::calculateTimeRemaining(qint64 received, qint64 total)
{
static quint64 lastRec = 0;
static uint lastTime = 0;
uint _time = QDateTime::currentDateTime().toMSecsSinceEpoch();
double _speed = (received - lastRec) / 1024.0 / (_time - lastTime) * 1000.0;
lastTime = _time;
lastRec = received;
uint difference = QDateTime::currentDateTime().toSecsSinceEpoch() - m_startTime;
if (difference > 0)
{
QString timeString;
qreal timeRemaining = (total - received) / (received / difference);
if (timeRemaining > 7200)
{
timeRemaining /= 3600;
int hours = int(timeRemaining + 0.5);
if (hours > 1)
timeString = tr("about %1 hours").arg(hours);
else
timeString = tr("about one hour");
}
else if (timeRemaining > 60)
{
timeRemaining /= 60;
int minutes = int(timeRemaining + 0.5);
if (minutes > 1)
timeString = tr("%1 minutes").arg(minutes);
else
timeString = tr("1 minute");
}
else if (timeRemaining <= 60)
{
int seconds = int(timeRemaining + 0.5);
if (seconds > 1)
timeString = tr("%1 seconds").arg(seconds);
else
timeString = tr("1 second");
}
ui->label_3->setText(tr("speed: %1 kb/s ").arg(_speed) + tr("Time remaining") + ": " + timeString);
}
}
void UpdaterDialog::on_btn_update_clicked()
{
if(!m_pDownloader)
{
m_pDownloader = new Downloader(this);
connect(m_pDownloader, &Downloader::doShowInfo, this, [&](const QString & s)
{
showStatus(s);
});
connect(m_pDownloader, &Downloader::onError, this, [&](QNetworkReply::NetworkError e)
{
QMetaEnum metaEnum = QMetaEnum::fromType<QNetworkReply::NetworkError>();
QString str = QString(metaEnum.valueToKey(e));
ui->show->appendPlainText(str);
});
connect(m_pDownloader, &Downloader::doFinished, this, [&]()
{
uint _end_time = QDateTime::currentSecsSinceEpoch();
uint _total_time = _end_time - m_startTime;
ui->label_3->setText("total time: " + QString::number(_total_time, 'g', 3) +
"s average speed: " + QString::number((m_totalSize / 1024.0 / _total_time), 'g', 3) + "kb/s");
ui->show->appendPlainText("download finished");
onDownloadFinished();
});
connect(m_pDownloader, &Downloader::doProgress, this, [&](quint64 received, quint64 total)
{
m_totalSize = total;
if (total > 0)
{
ui->progressBar->setMinimum(0);
ui->progressBar->setMaximum(100);
ui->progressBar->setValue((received * 100) / total);
calculateSizes(received, total);
calculateTimeRemaining(received, total);
}
else
{
ui->progressBar->setMinimum(0);
ui->progressBar->setMaximum(0);
ui->progressBar->setValue(-1);
ui->show->appendPlainText(tr("Downloading Updates") + "...");
}
});
}
m_pDownloader->setFileName(m_fileName);
m_startTime = QDateTime::currentDateTime().toSecsSinceEpoch();
QString _url = m_bDownloadFullExe ? m_fullUrl : m_patchUrl;
m_pDownloader->startDownload(_url);
}
void UpdaterDialog::on_btn_cancel_clicked()
{
if(!m_UpdateProc)
{
m_UpdateProc = new QProcess;
}
#if defined Q_OS_WIN
m_UpdateProc->setProgram(APPNAME + ".exe");
#elif defined Q_OS_LINUX
m_UpdateProc->setProgram("./" + APPNAME);
#endif
m_UpdateProc->start();
m_UpdateProc->waitForStarted();
QApplication::quit();
}
void UpdaterDialog::onDownloadFinished()
{
// ui->show->appendPlainText(m_pDownloader->fileName());
// ui->show->appendPlainText("m_bDownloadFullExe");
auto localInformation = QMessageBox::question(this, "update", "download finished\nstart update?");
if(localInformation == QMessageBox::Yes)
{
QString _appName;
if(!m_bDownloadFullExe)
{
//解压文件
QFileInfo f(m_pDownloader->getFile());
QString _path = f.fileName();
QZipReader * zipReader = new QZipReader(_path);
zipReader->extractAll(f.path());
_appName = APPNAME + ".exe";
}
else
{
_appName = m_pDownloader->fileName();
}
QFileInfo f2(QCoreApplication::applicationDirPath() + "/" + _appName);
if(f2.exists())
{
QDesktopServices::openUrl(f2.absoluteFilePath());
}
QApplication::quit();
}
}