RabbitCommon v2.2.6
Loading...
Searching...
No Matches
FrmUpdater.cpp
1// Copyright Copyright (c) Kang Lin studio, All Rights Reserved
2// Author Kang Lin <kl222@126.com>
3
4#include "FrmUpdater.h"
5#include "RabbitCommonDir.h"
6#include "RabbitCommonTools.h"
7#include "ui_FrmUpdater.h"
8#include <QUrl>
9#include <QStandardPaths>
10#include <QFinalState>
11#include <QJsonDocument>
12#include <QJsonObject>
13#include <QJsonArray>
14#include <QDomDocument>
15#include <QDomText>
16#include <QDomElement>
17#include <QProcess>
18#include <QDir>
19#include <QSsl>
20#include <QDesktopServices>
21#include <QInputDialog>
22#include <QMessageBox>
23#include <QMenu>
24#include <QSettings>
25#include <QLoggingCategory>
26#include <QRegularExpression>
27
28static Q_LOGGING_CATEGORY(log, "RabbitCommon.Updater")
29
30CFrmUpdater::CFrmUpdater(QWidget *parent) :
31 QWidget(parent),
32 ui(new Ui::CFrmUpdater),
33 m_InstallAutoStartupType(false),
34 m_ButtonGroup(this),
35 m_bDownload(false),
36 m_pStateDownloadSetupFile(nullptr)
37{
38 bool check = false;
39 setAttribute(Qt::WA_DeleteOnClose);
40 ui->setupUi(this);
41 ui->lbNewArch->hide();
42 ui->lbNewVersion->hide();
43 ui->progressBar->hide();
44 ui->cbHomePage->hide();
45 ui->pbOK->hide();
46
47 QSettings set(RabbitCommon::CDir::Instance()->GetFileUserConfigure(),
48 QSettings::IniFormat);
49 ui->cbPrompt->setChecked(set.value("Updater/Prompt", false).toBool());
50 ui->cbHomePage->setChecked(set.value("Updater/ShowHomePage", true).toBool());
51
52 check = connect(&m_TrayIcon,
53 SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
54 this,
55 SLOT(slotShowWindow(QSystemTrayIcon::ActivationReason)));
56 Q_ASSERT(check);
57 m_TrayIcon.setIcon(this->windowIcon());
58 m_TrayIcon.setToolTip(windowTitle() + " - "
59 + qApp->applicationDisplayName());
60
61 int id = set.value("Update/RadioButton", -2).toInt();
62 m_ButtonGroup.addButton(ui->rbEveryTime);
63 m_ButtonGroup.addButton(ui->rbEveryDate);
64 m_ButtonGroup.addButton(ui->rbEveryWeek);
65 m_ButtonGroup.addButton(ui->rbEveryMonth);
66 m_ButtonGroup.button(id)->setChecked(true);
67 check = connect(&m_ButtonGroup,
68 #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
69 SIGNAL(idClicked(int)),
70 #else
71 SIGNAL(buttonClicked(int)),
72 #endif
73 this, SLOT(slotButtonClickd(int)));
74 Q_ASSERT(check);
75 SetTitle();
76
77 ui->lbCurrentArch->setText(tr("Current archecture: %1")
78 .arg(QSysInfo::currentCpuArchitecture()));
79
80 QString szVerion = qApp->applicationVersion();
81#ifdef RabbitCommon_VERSION
82 if(szVerion.isEmpty())
83 szVerion = RabbitCommon_VERSION;
84#else
85 szVerion = "0.0.1";
86#endif
87 SetVersion(szVerion);
88
89 if(QSslSocket::supportsSsl())
90 {
91 QString szMsg;
92#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 3))
93 szMsg = "Build Version: " + QSslSocket::sslLibraryBuildVersionString();
94#endif
95 szMsg += "; Installed Version: " + QSslSocket::sslLibraryVersionString();
96 qInfo(log) << "QSslSocket support ssl:" << szMsg;
97 } else {
98 QString szMsg;
99#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 3))
100 szMsg = "BuildVersion: " + QSslSocket::sslLibraryBuildVersionString();
101#endif
102 qCritical(log) <<
103 "QSslSocket is not support ssl. The system is not install the OPENSSL dynamic library[" << szMsg << "]."
104 " Please install OPENSSL dynamic library [" << szMsg << "]";
105 }
106}
107
108CFrmUpdater::CFrmUpdater(QVector<QUrl> urls, QWidget *parent): CFrmUpdater(parent)
109{
110 if(urls.isEmpty())
111 {
112 // [Redirect configure file default urls]
113 QUrl github("https://github.com/KangLin/"
114 + qApp->applicationName() + "/raw/master/Update/update.json");
115 QUrl gitlab("https://gitlab.com/kl222/"
116 + qApp->applicationName() + "/-/raw/master/Update/update.json");
117 QUrl gitee("https://gitee.com/kl222/"
118 + qApp->applicationName() + "/raw/master/Update/update.json");
119 QUrl sourceforge("https://sourceforge.net/p/"
120 + qApp->applicationName() + "/ci/master/tree/Update/update.json?format=raw");
121 // [Redirect configure file default urls]
122 m_Urls << github << gitee << sourceforge << gitlab;
123 } else {
124 m_Urls = urls;
125 }
126 qDebug(log) << "Urls:" << m_Urls;
128}
129
130CFrmUpdater::~CFrmUpdater()
131{
132 qDebug(log) << "CFrmUpdater::~CFrmUpdater()";
133 m_DownloadFile.close();
134 if(m_Download)
135 m_Download.reset();
136 delete ui;
137}
138
191{
192 qDebug(log) << "Init State Machine";
193 QFinalState *sFinal = new QFinalState();
194 QState *sCheck = new QState();
195 QState *s = new QState();
196 QState *sDownloadConfigFile = new QState(s);
197 QState *sCheckConfigFile = new QState(s);
198 QState *sDownloadSetupFile = new QState(s);
199 QState *sUpdate = new QState(s);
200
201 bool check = connect(sFinal, SIGNAL(entered()),
202 this, SLOT(slotStateFinished()));
203 Q_ASSERT(check);
204
205 sCheck->addTransition(this, SIGNAL(sigError()), sFinal);
206 sCheck->addTransition(this, SIGNAL(sigFinished()), s);
207 check = connect(sCheck, SIGNAL(entered()), this, SLOT(slotCheck()));
208 Q_ASSERT(check);
209
210 s->addTransition(this, SIGNAL(sigError()), sFinal);
211 s->addTransition(this, SIGNAL(sigFinished()), sFinal);
212
213 s->setInitialState(sDownloadConfigFile);
214 sDownloadConfigFile->assignProperty(ui->lbState, "text", tr("Being Download config file"));
215 sDownloadConfigFile->addTransition(this, SIGNAL(sigFinished()), sCheckConfigFile);
216 check = connect(sDownloadConfigFile, SIGNAL(entered()),
217 this, SLOT(slotDownloadFile()));
218 Q_ASSERT(check);
219
220 sCheckConfigFile->addTransition(this, SIGNAL(sigDownLoadRedire()), sDownloadConfigFile);
221 sCheckConfigFile->addTransition(this, SIGNAL(sigFinished()), sDownloadSetupFile);
222 sCheckConfigFile->addTransition(ui->pbOK, SIGNAL(clicked()), sDownloadSetupFile);
223 sCheckConfigFile->assignProperty(ui->pbOK, "text", tr("OK(&O)"));
224 check = connect(sCheckConfigFile, SIGNAL(entered()), this, SLOT(slotCheckConfigFile()));
225 Q_ASSERT(check);
226
227 m_pStateDownloadSetupFile = sDownloadSetupFile;
228 sDownloadSetupFile->addTransition(this, SIGNAL(sigFinished()), sUpdate);
229 sDownloadSetupFile->assignProperty(ui->lbState, "text", tr("Being download update file"));
230 check = connect(sDownloadSetupFile, SIGNAL(entered()), this, SLOT(slotDownloadSetupFile()));
231 Q_ASSERT(check);
232
233 sUpdate->assignProperty(ui->lbState, "text", tr("Being install update"));
234 check = connect(sUpdate, SIGNAL(entered()), this, SLOT(slotUpdate()));
235 Q_ASSERT(check);
236
237 m_StateMachine.addState(sCheck);
238 m_StateMachine.addState(s);
239 m_StateMachine.addState(sFinal);
240 m_StateMachine.setInitialState(sCheck);
241 m_StateMachine.start();
242 return 0;
243}
244
245int CFrmUpdater::SetTitle(QImage icon, const QString &szTitle)
246{
247 QString title = szTitle;
248 if(szTitle.isEmpty())
249 title = qApp->applicationDisplayName();
250 ui->lbTitle->setText(title);
251
252 QPixmap pixmpa = QPixmap::fromImage(icon);
253 if(pixmpa.isNull())
254 pixmpa.load(":/icon/RabbitCommon/App", "PNG");
255 ui->lbTitleIcon->setPixmap(pixmpa);
256 return 0;
257}
258
259int CFrmUpdater::SetVersion(const QString &szVersion)
260{
261 m_szCurrentVersion = szVersion;
262 ui->lbCurrentVersion->setText(tr("Current version: %1")
263 .arg(m_szCurrentVersion));
264 return 0;
265}
266
267void CFrmUpdater::slotStateFinished()
268{
269 qDebug(log) << "slotStateFinished()";
270 if(m_Download)
271 m_Download.reset();
272}
273
274void CFrmUpdater::slotCheck()
275{
276 qDebug(log) << "CFrmUpdater::slotCheck()";
277 QSettings set(RabbitCommon::CDir::Instance()->GetFileUserConfigure(),
278 QSettings::IniFormat);
279 QDateTime d = set.value("Update/DateTime").toDateTime();
280 set.setValue("Update/DateTime", QDateTime::currentDateTime());
281 if(m_bDownload)
282 {
283 emit sigFinished();
284 return;
285 }
286
287 int n = 0;
288 if(ui->rbEveryDate->isChecked())
289 n = 1;
290 else if(ui->rbEveryWeek->isChecked())
291 n = 7;
292 else if(ui->rbEveryMonth->isChecked())
293 n = 30;
294
295 if(n <= d.daysTo(QDateTime::currentDateTime()))
296 emit sigFinished();
297 else
298 emit sigError();
299}
300
301// [Process the signals of RabbitCommon::CDownload]
302void CFrmUpdater::slotDownloadError(int nErr, const QString szError)
303{
304 ui->progressBar->hide();
305 ui->progressBar->setRange(0, 100);;
306 QString szMsg;
307 szMsg = tr("Failed:") + tr("Download file is Failed.");
308 if(!szError.isEmpty())
309 szMsg += "(" + szError + ")";
310 ui->lbState->setText(szMsg);
311 qCritical(log) << szMsg << nErr;
312 emit sigError();
313}
314
315void CFrmUpdater::slotDownloadFileFinished(const QString szFile)
316{
317 qDebug(log) << "slotDownloadFileFinished:" << szFile;
318 ui->progressBar->hide();
319 ui->progressBar->setRange(0, 100);;
320 if(m_DownloadFile.isOpen())
321 m_DownloadFile.close();
322
323 QString szTmp
324 = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
325 szTmp = szTmp + QDir::separator() + "Rabbit"
326 + QDir::separator() + qApp->applicationName();
327
328 QString szFileName(m_ConfigFile.szFileName);
329 if(szFileName.isEmpty())
330 {
331 szFileName = szFile.mid(szFile.lastIndexOf("/"));
332 }
333 if(szFileName.left(1) != "/" && szFileName.left(1) != "\\")
334 szFileName = QDir::separator() + szFileName;
335 QString f = szTmp + szFileName;
336 if(QFile::exists(f))
337 QFile::remove(f);
338#if HAVE_TEST
339 if(QFile::copy(szFile, f))
340#else
341 if(QFile::rename(szFile, f))
342#endif
343 {
344 m_DownloadFile.setFileName(f);
345 qInfo(log) << "Download finished: rename"
346 << szFile << "to" << f;
347 } else {
348 qCritical(log) << "Download finished. rename fail from"
349 << szFile << "to" << f;
350 m_DownloadFile.setFileName(szFile);
351 }
352 emit sigFinished();
353}
354
355void CFrmUpdater::slotDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
356{
357 if(ui->progressBar->isHidden())
358 {
359 ui->progressBar->show();
360 ui->progressBar->setRange(0, static_cast<int>(bytesTotal));
361 }
362 if(ui->progressBar->maximum() != bytesTotal)
363 ui->progressBar->setRange(0, static_cast<int>(bytesTotal));
364
365 ui->progressBar->setValue(static_cast<int>(bytesReceived));
366 if(bytesTotal > 0) {
367 QString szInfo = tr("Downloading %1% [%2/%3]")
368 .arg(QString::number(bytesReceived * 100 / bytesTotal))
369 .arg(QString::number(bytesReceived)).arg(QString::number(bytesTotal));
370 //qDebug(log) << szInfo;
371 m_TrayIcon.setToolTip(windowTitle() + " - "
372 + qApp->applicationDisplayName()
373 + ": " + szInfo);
374 }
375}
376// [Process the signals of RabbitCommon::CDownload]
377
378void CFrmUpdater::slotDownloadFile()
379{
380 qDebug(log) << "CFrmUpdater::slotDownloadFile";
381 // [Use RabbitCommon::CDownload download file]
382 if(!m_Urls.isEmpty())
383 {
384 m_Download = QSharedPointer<RabbitCommon::CDownload>(
385 new RabbitCommon::CDownload(), &QObject::deleteLater);
386 bool check = connect(m_Download.data(), SIGNAL(sigFinished(const QString)),
387 this, SLOT(slotDownloadFileFinished(const QString)));
388 Q_ASSERT(check);
389 check = connect(m_Download.data(), SIGNAL(sigError(int, const QString)),
390 this, SLOT(slotDownloadError(int, const QString)));
391 Q_ASSERT(check);
392 check = connect(m_Download.data(), SIGNAL(sigDownloadProgress(qint64, qint64)),
393 this, SLOT(slotDownloadProgress(qint64, qint64)));
394 Q_ASSERT(check);
395 m_Download->Start(m_Urls);
396 }
397 // [Use RabbitCommon::CDownload download file]
398}
399
400void CFrmUpdater::slotCheckConfigFile()
401{
402 m_TrayIcon.setToolTip(windowTitle() + " - "
403 + qApp->applicationDisplayName());
404 qDebug(log) << "CFrmUpdater::slotCheckConfigFile()";
405
406 // Redirect
407 int nRet = 0;
409 if(nRet <= 0) return;
410 if(2 == nRet)
411 {
412 QString szText(tr("There is laster version"));
413 ui->lbState->setText(szText);
414 qInfo(log) << szText;
415 emit sigError();
416 return;
417 }
418 if(1 == nRet)
420}
421
437{
438 int nRet = 0;
439 qDebug(log) << "CFrmUpdater::CheckRedirectConfigFile()"
440 << m_DownloadFile.fileName();
441
442 QVector<CONFIG_REDIRECT> conf;
443 nRet = GetRedirectFromFile(m_DownloadFile.fileName(), conf);
444 if(nRet) {
445 if(nRet < 0) {
446 QString szError = tr("Failed:") + tr("%2 process the file: %1")
447 .arg(m_DownloadFile.fileName()).arg(nRet);
448 ui->lbState->setText(szError);
449 qCritical(log) << szError;
450 emit sigError();
451 }
452 return nRet;
453 }
454
455 CONFIG_REDIRECT redirect;
456 for(auto it = conf.begin(); it != conf.end(); it++) {
457
458 QString szVersion = it->szVersion;
459 if(szVersion.isEmpty())
460 {
461 QString szError = tr("Failed:") + tr("Configure file content error:")
462 + m_DownloadFile.fileName();
463 ui->lbState->setText(szError);
464 qCritical(log) << szError;
465 emit sigError();
466 return -2;
467 }
468
469 if(CompareVersion(szVersion, m_szCurrentVersion) <= 0)
470 continue;
471
472 QString szMinVersion = it->szMinUpdateVersion;
473 if(!szMinVersion.isEmpty()) {
474 if(CompareVersion(szMinVersion, m_szCurrentVersion) > 0)
475 continue;
476 }
477
478 redirect = *it;
479 break;
480 }
481
482 if(redirect.szVersion.isEmpty())
483 return 2;
484
485 CONFIG_FILE file;
486 foreach (auto f, redirect.files) {
487 if(!f.szSystem.isEmpty()) {
488 if(QSysInfo::productType() != f.szSystem)
489 continue;
490 }
491 if(!f.szArchitecture.isEmpty())
492 {
493 QString szArchitecture = QSysInfo::currentCpuArchitecture();
494#if defined(Q_OS_WIN) || defined(Q_OS_LINUX)
495 if(!szArchitecture.compare("i386", Qt::CaseInsensitive)
496 && !f.szArchitecture.compare("x86_64", Qt::CaseInsensitive))
497 continue;
498#else
499 if(szArchitecture != f.szArchitecture)
500 continue;
501#endif
502 }
503 file = f;
504 break;
505 }
506
507 m_Urls = file.urls;
508 if(m_Urls.isEmpty())
509 {
510 if(redirect.files.isEmpty()) {
511 // [Update configure file default urls]
512 QUrl github("https://github.com/KangLin/"
513 + qApp->applicationName() + "/releases/download/"
514 + redirect.szVersion + "/update.json");
515 m_Urls.push_back(github);
516 QUrl sourceforge("https://sourceforge.net/projects/"
517 + qApp->applicationName() +"/files/"
518 + redirect.szVersion + "/update.json?viasf=1");
519 m_Urls.push_back(sourceforge);
520 // [Update configure file default urls]
521 } else {
522 QString szError;
523 szError = tr("Failed:")
524 + tr("Don't find the urls in configure file:")
525 + m_DownloadFile.fileName()
526 + "; " + tr("Current version:") + m_szCurrentVersion
527 + "; " + tr("version:") + redirect.szVersion
528 + "; " + tr("min update version:")
529 + redirect.szMinUpdateVersion;
530 qCritical(log) << szError;
531 ui->lbState->setText(szError);
532 return -3;
533 }
534 }
535
536 qInfo(log) << "Redirect. Version:" << redirect.szVersion << m_Urls;
537
538 emit sigDownLoadRedire();
539
540 return 0;
541}
542
576{
577 int nRet = 0;
578 qDebug(log) << "CFrmUpdater::CheckUpdateConfigFile()";
579 CONFIG_INFO info;
580 nRet = GetConfigFromFile(m_DownloadFile.fileName(), info);
581 if(nRet) {
582 QString szError = tr("Failed:") + tr("%2 process the file: %1")
583 .arg(m_DownloadFile.fileName()).arg(nRet);
584 ui->lbState->setText(szError);
585 qCritical(log) << szError;
586 emit sigError();
587 return nRet;
588 }
589
590 if(CompareVersion(info.version.szVerion, m_szCurrentVersion) <= 0)
591 {
592 QString szError;
593 szError = tr("There is laster version");
594 ui->lbState->setText(szError);
595 qInfo(log) << szError;
596 emit sigError();
597 return -4;
598 }
599
600 if(info.files.isEmpty()) {
601 QString szError;
602 szError = tr("Failed:") + tr("There is not files in the configure file ")
603 + m_DownloadFile.fileName();
604 ui->lbState->setText(szError);
605 qCritical(log) << szError;
606 emit sigError();
607 return -5;
608 }
609
610 QString szArchitecture = QSysInfo::currentCpuArchitecture();
611 CONFIG_FILE file;
612 foreach (auto f, info.files) {
613 if(f.szSystem.compare(QSysInfo::productType(), Qt::CaseInsensitive))
614 continue;
615
616#if defined(Q_OS_WIN) || defined(Q_OS_LINUX)
617 if(!szArchitecture.compare("i386", Qt::CaseInsensitive)
618 && !f.szArchitecture.compare("x86_64", Qt::CaseInsensitive))
619 continue;
620#else
621 if(szArchitecture != f.szArchitecture)
622 continue;
623#endif
624 file = f;
625 break;
626 }
627
628 if(file.szSystem.compare(QSysInfo::productType(), Qt::CaseInsensitive)) {
629 QString szErr;
630 szErr = tr("Failed:")
631 + tr("The system or architecture is not exist in the configure file ")
632 + m_DownloadFile.fileName();
633 ui->lbState->setText(szErr);
634 qCritical(log) << szErr;
635 emit sigError();
636 return -6;
637 }
638
639 m_Info.version = info.version;
640 m_ConfigFile = file;
641
642 ui->lbNewVersion->setText(tr("New version: %1").arg(info.version.szVerion));
643 ui->lbNewVersion->show();
644 ui->lbNewArch->setText(tr("New architecture: %1").arg(file.szArchitecture));
645 ui->lbNewArch->show();
646 ui->lbState->setText(tr("There is a new version, is it updated?"));
647 if(info.version.bForce)
648 {
649 qDebug(log) << "Force update";
650 emit sigFinished();
651 }
652 else
653 {
654 ui->cbHomePage->show();
655 ui->cbPrompt->show();
656 ui->pbOK->setText(tr("OK(&O)"));
657 ui->pbOK->show();
658 if(!CheckPrompt(info.version.szVerion) && this->isHidden())
659 emit sigError();
660 else
661 show();
662 }
663
664 return nRet;
665}
666
678int CFrmUpdater::GetRedirectFromFile(const QString& szFile, QVector<CONFIG_REDIRECT> &conf)
679{
680 QFile f(szFile);
681 if(!f.open(QFile::ReadOnly))
682 {
683 QString szError = tr("Open file fail").arg(szFile);
684 qCritical(log) << szError;
685 return -1;
686 }
687
688 QJsonDocument doc;
689 doc = QJsonDocument::fromJson(f.readAll());
690 f.close();
691 if(!doc.isObject())
692 {
693 QString szError = tr("Parse file %1 fail. It isn't configure file")
694 .arg(f.fileName());
695 qCritical(log) << szError;
696 return -2;
697 }
698
699 QJsonObject objRoot = doc.object();
700 if(!objRoot.contains("redirect"))
701 return 1;
702
703 QJsonArray arrRedirect = objRoot["redirect"].toArray();
704 for(auto it = arrRedirect.begin(); it != arrRedirect.end(); it++) {
705 QJsonObject obj = it->toObject();
706 CONFIG_REDIRECT objRedirect;
707 objRedirect.szVersion = obj["version"].toString();
708 objRedirect.szMinUpdateVersion = obj["min_update_version"].toString();
709 qDebug(log) << "version:" << objRedirect.szVersion
710 << "min_update_version:" << objRedirect.szMinUpdateVersion;
711
712 QJsonArray objFiles = obj["files"].toArray();
713 for(auto it = objFiles.begin(); it != objFiles.end(); it++) {
714 QJsonObject f = it->toObject();
715 CONFIG_FILE file;
716 file.szSystem = f["os"].toString();
717 file.szSystemMinVersion = f["os_min_version"].toString();
718 file.szArchitecture = f["arch"].toString();
719 file.szArchitectureMinVersion = f["arch_min_version"].toString();
720 file.szMd5sum = f["md5"].toString();
721 file.szFileName = f["name"].toString();
722
723 QJsonArray urls = f["urls"].toArray();
724 foreach(auto u, urls)
725 {
726 file.urls.append(u.toString());
727 }
728
729 objRedirect.files.append(file);
730 //*
731 qDebug(log) << "OS:" << file.szSystem
732 << "os_min_version:" << file.szSystemMinVersion
733 << "arch:" << file.szArchitecture
734 << "arch_min_version:" << file.szArchitectureMinVersion
735 << "md5:" << file.szMd5sum
736 << "name:" << file.szFileName
737 << "urls:" << file.urls;//*/
738 }
739
740 conf.append(objRedirect);
741 }
742
743 return 0;
744}
745
798int CFrmUpdater::GetConfigFromFile(const QString &szFile, CONFIG_INFO& conf)
799{
800 QFile file(szFile);
801 if(!file.open(QFile::ReadOnly)) {
802 qDebug(log) << "The file isn't opened:" << szFile;
803 return -1;
804 }
805
806 QJsonDocument doc;
807 doc = QJsonDocument::fromJson(file.readAll());
808 file.close();
809 if(!doc.isObject())
810 {
811 qCritical(log) << "Parser configure file fail." << szFile;
812 return -2;
813 }
814
815 QJsonObject obj = doc.object();
816 if(obj.contains("version")) {
817 QJsonObject objVersion = obj["version"].toObject();
818 conf.version.szVerion = objVersion["version"].toString();
819 conf.version.szMinUpdateVersion = objVersion["min_update_version"].toString();
820 conf.version.szTime = objVersion["time"].toString();
821 conf.version.szInfomation = objVersion["information"].toString();
822 conf.version.szHome = objVersion["home"].toString();
823 conf.version.bForce = objVersion["force"].toBool();
824 //*
825 qDebug(log) << "Current version:" << m_szCurrentVersion
826 << "version:" << conf.version.szVerion
827 << "minUpdateVersion:" << conf.version.szMinUpdateVersion
828 << "time:" << conf.version.szTime
829 << "information:" << conf.version.szInfomation
830 << "home:" << conf.version.szHome
831 << "bForce:" << conf.version.bForce
832 ;//*/
833 }
834
835 if(!obj.contains("files")) {
836 qDebug(log) << "Configure file isn't contains files array";
837 return 0;
838 }
839
840 QJsonArray objFiles = obj["files"].toArray();
841 for(auto it = objFiles.begin(); it != objFiles.end(); it++) {
842 QJsonObject f = it->toObject();
843 CONFIG_FILE file;
844 file.szSystem = f["os"].toString();
845 file.szSystemMinVersion = f["os_min_version"].toString();
846 file.szArchitecture = f["arch"].toString();
847 file.szArchitectureMinVersion = f["arch_min_version"].toString();
848 file.szMd5sum = f["md5"].toString();
849 file.szFileName = f["name"].toString();
850
851 QJsonArray urls = f["urls"].toArray();
852 foreach(auto u, urls)
853 {
854 file.urls.append(u.toString());
855 }
856
857 conf.files.append(file);
858 //*
859 qDebug(log) << "OS:" << file.szSystem
860 << "os_min_version:" << file.szSystemMinVersion
861 << "arch:" << file.szArchitecture
862 << "arch_min_version:" << file.szArchitectureMinVersion
863 << "md5:" << file.szMd5sum
864 << "name:" << file.szFileName
865 << "urls:" << file.urls;//*/
866 }
867
868 return 0;
869}
870
871void CFrmUpdater::slotDownloadSetupFile()
872{
873 qDebug(log) << "CFrmUpdater::slotDownloadSetupFile()";
874 ui->pbOK->setText(tr("Hide"));
875 ui->lbState->setText(tr("Download ......"));
876 if(IsDownLoad())
877 emit sigFinished();
878 else
879 {
880 m_Urls = m_ConfigFile.urls;
881 slotDownloadFile();
882 }
883}
884
885void CFrmUpdater::slotUpdate()
886{
887 m_TrayIcon.setToolTip(windowTitle() + " - "
888 + qApp->applicationDisplayName());
889 ui->lbState->setText(tr("Being install update ......"));
890 ui->progressBar->hide();
891 ui->progressBar->setRange(0, 100);;
892 //qDebug(log) << "CFrmUpdater::slotUpdate()";
893
894 // Check file md5sum
895 bool bSuccess = false;
896 do {
897 if(!m_DownloadFile.open(QIODevice::ReadOnly))
898 {
899 QString szErr;
900 szErr = tr("Failed:") + tr("Don't open download file ")
901 + m_DownloadFile.fileName();
902 qCritical(log) << szErr;
903 ui->lbState->setText(szErr);
904 break;
905 }
906 QCryptographicHash md5sum(QCryptographicHash::Md5);
907 if(!md5sum.addData(&m_DownloadFile))
908 {
909 QString szErr;
910 szErr = tr("Failed:") + tr("Don't open download file ")
911 + m_DownloadFile.fileName();
912 qCritical(log) << szErr;
913 ui->lbState->setText(szErr);
914 break;
915 }
916 if(md5sum.result().toHex() != m_ConfigFile.szMd5sum)
917 {
918 QString szFail;
919 szFail = tr("Failed:") + tr("Md5sum is different. ")
920 + "\n" + tr("Download file md5sum: ")
921 + md5sum.result().toHex()
922 + "\n" + tr("md5sum in Update.xml:")
923 + m_ConfigFile.szMd5sum;
924 ui->lbState->setText(szFail);
925 qCritical(log) << szFail;
926 break;
927 }
928 bSuccess = true;
929 } while(0);
930
931 m_DownloadFile.close();
932 if(!bSuccess)
933 {
934 emit sigError();
935 return;
936 }
937
938 // Exec download file
939 bSuccess = false;
940 do {
941 //修改文件执行权限
942 /*QFileInfo info(m_szDownLoadFile);
943 if(!info.permission(QFile::ExeUser))
944 {
945 //修改文件执行权限
946 QString szErr = tr("Download file don't execute permissions. Please modify permission then manually execute it.\n%1").arg(m_szDownLoadFile);
947 slotError(-2, szErr);
948 return;
949 }*/
950
951 QProcess proc;
952 QFileInfo fi(m_DownloadFile.fileName());
953 if(fi.suffix().compare("gz", Qt::CaseInsensitive))
954 {
955 QString szCmd;
956 szCmd = m_DownloadFile.fileName();
957 //启动安装程序
958 qInfo(log) << "Start"
959 << szCmd
960 << "in a new process, and detaches from it.";
961 if(!proc.startDetached(szCmd))
962 {
963 qInfo(log) << "Start new process fail."
964 << "Use system installer to install"
965 << m_DownloadFile.fileName();
966 QUrl url(m_DownloadFile.fileName());
967 if(!QDesktopServices::openUrl(url))
968 {
969 QString szErr = tr("Failed:")
970 + tr("Execute install program error.%1")
971 .arg(m_DownloadFile.fileName());
972 ui->lbState->setText(szErr);
973 break;
974 }
975 }
976 } else {
977 QString szInstall = fi.absolutePath() + QDir::separator() + "setup.sh";
978 QFile f(szInstall);
979 if(!f.open(QFile::WriteOnly))
980 {
981 QString szErr = tr("Failed:")
982 + tr("Open file %1 fail").arg(fi.absolutePath());
983 ui->lbState->setText(szErr);
984 break;
985 }
986 QString szCmd = InstallScript(m_DownloadFile.fileName(),
987 qApp->applicationName());
988 f.write(szCmd.toStdString().c_str());
989 qDebug(log) << szCmd << szInstall;
990 f.close();
991
992 //启动安装程序
994 QStringList() << szInstall))
995 {
996 QString szErr = tr("Failed:") + tr("Execute") + "/bin/bash "
997 + szInstall + "fail";
998 ui->lbState->setText(szErr);
999 break;
1000 }
1001
1002 //启动程序
1003// int nRet = QMessageBox::information(this, tr("Run"),
1004// tr("Run after install"),
1005// QMessageBox::Yes|QMessageBox::No,
1006// QMessageBox::Yes);
1007// if(QMessageBox::No == nRet)
1008// break;
1009// QString szProgram = "/opt/"
1010// + qApp->applicationName()
1011// + "/install1.sh start "
1012// + qApp->applicationName();
1013// QProcess exe;
1014// if(!exe.startDetached(szProgram))
1015// {
1016// QString szErr = tr("Failed:") + tr("Execute program error.%1")
1017// .arg(szProgram);
1018// ui->lbState->setText(szErr);
1019// break;
1020// }
1021 }
1022
1023 ui->lbState->setText(tr("The installer has started, Please close the application"));
1024
1025 //system(m_DownloadFile.fileName().toStdString().c_str());
1026 //int nRet = QProcess::execute(m_DownloadFile.fileName());
1027 //qDebug(log) << "QProcess::execute return: " << nRet;
1028
1029 bSuccess = true;
1030 } while(0);
1031
1032 QProcess procHome;
1033 QString szHome = m_Info.version.szHome;
1034 if((!bSuccess || ui->cbHomePage->isChecked()) && !szHome.isEmpty())
1035 if(!procHome.startDetached(szHome))
1036 {
1037 QUrl url(szHome);
1038 if(!QDesktopServices::openUrl(url))
1039 {
1040 QString szErr = tr("Failed:") + tr("Open home page fail");
1041 ui->lbState->setText(szErr);
1042 }
1043 }
1044
1045 if(bSuccess)
1046 {
1047 emit sigFinished();
1048 qApp->quit();
1049 return;
1050 }
1051
1052 emit sigError();
1053 QUrl url(szHome);
1054 if(!QDesktopServices::openUrl(url))
1055 {
1056 QString szErr = tr("Open home page fail");
1057 qCritical(log) << szErr;
1058 }
1059}
1060
1061QString CFrmUpdater::InstallScript(const QString szDownLoadFile,
1062 const QString szApplicationName)
1063{
1064 QFileInfo fi(szDownLoadFile);
1065 QString szCmd;
1066 szCmd = "#!/bin/bash\n";
1067 szCmd += "set -e\n";
1068 szCmd += "if [ ! -d /opt/" + szApplicationName + " ]; then\n";
1069 szCmd += " mkdir -p /opt/" + szApplicationName + "\n";
1070 szCmd += "fi\n";
1071 szCmd += "cd /opt/" + szApplicationName + "\n";
1072 szCmd += "if [ -f install1.sh ]; then\n";
1073 szCmd += " ./install1.sh remove " + szApplicationName + "\n";
1074 //szCmd += " rm -fr *\n";
1075 szCmd += "fi\n";
1076 szCmd += "cp " + szDownLoadFile + " ." + "\n";
1077 szCmd += "tar xvfz " + fi.fileName() + "\n";
1078 szCmd += "rm " + fi.fileName() + "\n";
1079
1080 //See: Install/install.sh
1081 szCmd += "./install1.sh ";
1082 if(m_InstallAutoStartupType)
1083 szCmd += "install_autostart";
1084 else
1085 szCmd += "install";
1086 //启动程序
1087 int nRet = QMessageBox::information(this, tr("Run"),
1088 tr("Run after install"),
1089 QMessageBox::Yes|QMessageBox::No,
1090 QMessageBox::Yes);
1091 if(QMessageBox::Yes == nRet)
1092 {
1093 szCmd += "_run";
1094 }
1095 szCmd += " " + szApplicationName + "\n";
1096 return szCmd;
1097}
1098
1108int CFrmUpdater::CompareVersion(const QString &newVersion, const QString &currentVersion)
1109{
1110 int nRet = 0;
1111 QString sN = newVersion;
1112 QString sC = currentVersion;
1113
1114 if(sN.isEmpty() || sC.isEmpty())
1115 return sN.length() - sC.length();
1116
1117 sN = sN.replace("-", ".");
1118 sC = sC.replace("-", ".");
1119
1120 QStringList szNew = sN.split(".");
1121 QStringList szCur = sC.split(".");
1122
1123 int count = qMin(szNew.length(), szCur.length());
1124 qDebug(log) << "count:" << count;
1125
1126 if(count < 1)
1127 return szNew.length() - szCur.length();
1128
1129 QString firstNew = szNew.at(0);
1130 QString firstCur = szCur.at(0);
1131 firstNew = firstNew.remove(QChar('v'), Qt::CaseInsensitive);
1132 firstCur = firstCur.remove(QChar('v'), Qt::CaseInsensitive);
1133 nRet = firstNew.toInt() - firstCur.toInt();
1134 if(nRet)
1135 return nRet;
1136
1137 if(count < 2)
1138 return sN.length() - sC.length();
1139 nRet = szNew.at(1).toInt() - szCur.at(1).toInt();
1140 if(nRet)
1141 return nRet;
1142
1143 if(count < 3)
1144 return sN.length() - sC.length();
1145 return szNew.at(2).toInt() - szCur.at(2).toInt();
1146}
1147
1153{
1154 bool bRet = false;
1155 QString szTmp
1156 = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
1157 szTmp = szTmp + QDir::separator() + "Rabbit"
1158 + QDir::separator() + qApp->applicationName();
1159
1160 QString szFile = szTmp + QDir::separator() + m_ConfigFile.szFileName;
1161
1162 QFile f(szFile);
1163 if(!f.open(QIODevice::ReadOnly))
1164 return false;
1165
1166 m_DownloadFile.setFileName(szFile);
1167 do {
1168 QCryptographicHash md5sum(QCryptographicHash::Md5);
1169 if(!md5sum.addData(&f))
1170 {
1171 bRet = false;
1172 break;
1173 }
1174 if(md5sum.result().toHex() != m_ConfigFile.szMd5sum)
1175 {
1176 bRet = false;
1177 break;
1178 }
1179 else
1180 {
1181 bRet = true;
1182 break;
1183 }
1184 } while(0);
1185 f.close();
1186 return bRet;
1187}
1188
1189void CFrmUpdater::on_pbOK_clicked()
1190{
1191 qDebug(log) << "CFrmUpdater::on_pbOK_clicked()";
1192 if(!m_pStateDownloadSetupFile->active())
1193 return;
1194
1195 m_TrayIcon.show();
1196 hide();
1197}
1198
1199void CFrmUpdater::on_pbClose_clicked()
1200{
1201 if(m_StateMachine.isRunning())
1202 {
1203 QMessageBox::StandardButton ret = QMessageBox::warning(this, tr("Close"),
1204 tr("Is updating, be sure to close?"), QMessageBox::Yes|QMessageBox::No);
1205 if(QMessageBox::No == ret)
1206 {
1207 return;
1208 }
1209 }
1210 emit sigError();
1211 close();
1212}
1213
1214void CFrmUpdater::slotButtonClickd(int id)
1215{
1216 QSettings set(RabbitCommon::CDir::Instance()->GetFileUserConfigure(), QSettings::IniFormat);
1217 set.setValue("Update/RadioButton", id);
1218}
1219
1221{
1222 QCommandLineParser parser;
1223 int nRet = GenerateUpdateJson(parser);
1224 parser.process(qApp->arguments());
1225 return nRet;
1226}
1227
1228int CFrmUpdater::GenerateUpdateJson(QCommandLineParser &parser)
1229{
1230 QString szFile;
1231 CONFIG_INFO info;
1232 CONFIG_TYPE type;
1233 int nRet = GetConfigFromCommandLine(parser, szFile, info, type);
1234 if(nRet)
1235 return nRet;
1236 return GenerateJsonFile(szFile, info, type);
1237}
1238
1247int CFrmUpdater::GenerateJsonFile(const QString &szFile, const CONFIG_INFO &info, CONFIG_TYPE type)
1248{
1249 QJsonDocument doc;
1250
1251 QJsonObject version;
1252 version.insert("version", info.version.szVerion);
1253 version.insert("min_update_version", info.version.szMinUpdateVersion);
1254 version.insert("time", info.version.szTime);
1255 version.insert("information", info.version.szInfomation);
1256 version.insert("home", info.version.szHome);
1257 version.insert("force", info.version.bForce);
1258
1259 QJsonArray files;
1260 foreach (auto f, info.files) {
1261 QJsonObject file;
1262 file.insert("os", f.szSystem);
1263 if(!f.szSystemMinVersion.isEmpty())
1264 file.insert("os_min_version", f.szSystemMinVersion);
1265 file.insert("arch", f.szArchitecture);
1266 if(!f.szArchitectureMinVersion.isEmpty())
1267 file.insert("arch_min_version", f.szArchitectureMinVersion);
1268 file.insert("md5", f.szMd5sum);
1269 file.insert("name", f.szFileName);
1270 QJsonArray urls;
1271 foreach (auto u, f.urls) {
1272 urls.append(u.toString());
1273 }
1274 file.insert("urls", urls);
1275 files.append(file);
1276 }
1277
1278 switch(type) {
1279 case CONFIG_TYPE::VERSION:
1280 doc.setObject(version);
1281 break;
1282 case CONFIG_TYPE::FILE:
1283 doc.setObject(files[0].toObject());
1284 break;
1285 case CONFIG_TYPE::VERSION_FILE:
1286 {
1287 QJsonObject root;
1288 root.insert("version", version);
1289 root.insert("files", files);
1290 doc.setObject(root);
1291 }
1292 default:
1293 break;
1294 };
1295
1296 QFile f(szFile);
1297 if(!f.open(QIODevice::WriteOnly))
1298 {
1299 qCritical(log) << "Open file fail:" << f.fileName();
1300 return -1;
1301 }
1302 f.write(doc.toJson());
1303 f.close();
1304 return 0;
1305}
1306
1307int CFrmUpdater::GenerateUpdateXmlFile(const QString &szFile, const CONFIG_INFO &info, CONFIG_TYPE &type)
1308{
1309 QDomDocument doc;
1310 QDomProcessingInstruction ins;
1311 //<?xml version='1.0' encoding='UTF-8'?>
1312 ins = doc.createProcessingInstruction("xml", "version=\'1.0\' encoding=\'UTF-8\'");
1313 doc.appendChild(ins);
1314 QDomElement root = doc.createElement("UPDATE");
1315 doc.appendChild(root);
1316
1317 QDomText version = doc.createTextNode("VERSION");
1318 version.setData(info.version.szVerion);
1319 QDomElement eVersion = doc.createElement("VERSION");
1320 eVersion.appendChild(version);
1321 root.appendChild(eVersion);
1322
1323 QDomText time = doc.createTextNode("TIME");
1324 time.setData(info.version.szTime);
1325 QDomElement eTime = doc.createElement("TIME");
1326 eTime.appendChild(time);
1327 root.appendChild(eTime);
1328
1329 QDomText i = doc.createTextNode("INFO");
1330 i.setData(info.version.szInfomation);
1331 QDomElement eInfo = doc.createElement("INFO");
1332 eInfo.appendChild(i);
1333 root.appendChild(eInfo);
1334
1335 QDomText force = doc.createTextNode("FORCE");
1336 force.setData(QString::number(info.version.bForce));
1337 QDomElement eForce = doc.createElement("FORCE");
1338 eForce.appendChild(force);
1339 root.appendChild(eForce);
1340
1341 CONFIG_FILE file = info.files[0];
1342 QDomText system = doc.createTextNode("SYSTEM");
1343 system.setData(file.szSystem);
1344 QDomElement eSystem = doc.createElement("SYSTEM");
1345 eSystem.appendChild(system);
1346 root.appendChild(eSystem);
1347
1348 QDomText arch = doc.createTextNode("ARCHITECTURE");
1349 arch.setData(file.szArchitecture);
1350 QDomElement architecture = doc.createElement("ARCHITECTURE");
1351 architecture.appendChild(arch);
1352 root.appendChild(architecture);
1353
1354 QDomText md5 = doc.createTextNode("MD5SUM");
1355 md5.setData(file.szMd5sum);
1356 QDomElement eMd5 = doc.createElement("MD5SUM");
1357 eMd5.appendChild(md5);
1358 root.appendChild(eMd5);
1359
1360 QDomText fileName = doc.createTextNode("FILENAME");
1361 fileName.setData(file.szFileName);
1362 QDomElement eFileName = doc.createElement("FILENAME");
1363 eFileName.appendChild(fileName);
1364 root.appendChild(eFileName);
1365
1366 foreach(auto u, file.urls)
1367 {
1368 QDomText url = doc.createTextNode("URL");
1369 url.setData(u.toString());
1370 QDomElement eUrl = doc.createElement("URL");
1371 eUrl.appendChild(url);
1372 root.appendChild(eUrl);
1373 }
1374
1375 QDomText urlHome = doc.createTextNode("HOME");
1376 urlHome.setData(info.version.szHome);
1377 QDomElement eUrlHome = doc.createElement("HOME");
1378 eUrlHome.appendChild(urlHome);
1379 root.appendChild(eUrlHome);
1380
1381 QDomText min = doc.createTextNode("MIN_UPDATE_VERSION");
1382 min.setData(info.version.szMinUpdateVersion);
1383 QDomElement eMin = doc.createElement("MIN_UPDATE_VERSION");
1384 eMin.appendChild(min);
1385 root.appendChild(eMin);
1386
1387 QFile f;
1388 f.setFileName(szFile);
1389 if(!f.open(QIODevice::WriteOnly))
1390 {
1391 qCritical(log)
1392 << "CFrmUpdater::GenerateUpdateXml file open file fail:"
1393 << f.fileName();
1394 return -1;
1395 }
1396 QTextStream stream(&f);
1397#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1398 stream.setCodec("UTF-8");
1399#endif
1400 doc.save(stream, 4);
1401 f.close();
1402 return 0;
1403}
1404
1406{
1407 QCommandLineParser parser;
1408 int nRet = GenerateUpdateXml(parser);
1409 parser.process(qApp->arguments());
1410 return nRet;
1411}
1412
1413int CFrmUpdater::GenerateUpdateXml(QCommandLineParser &parser)
1414{
1415 QString szFile;
1416 CONFIG_INFO info;
1417 CONFIG_TYPE type;
1418 int nRet = GetConfigFromCommandLine(parser, szFile, info, type);
1419 if(nRet)
1420 return nRet;
1421 return GenerateUpdateXmlFile(szFile + ".xml", info, type);
1422}
1423
1433int CFrmUpdater::GetConfigFromCommandLine(/*[in]*/QCommandLineParser &parser,
1434 /*[out]*/QString &szFile,
1435 /*[out]*/CONFIG_INFO &info,
1436 /*[out]*/CONFIG_TYPE &type)
1437{
1438 QString szFileName;
1439#if defined (Q_OS_WIN)
1440 szFileName = qApp->applicationName() + "_" + m_szCurrentVersion + "_Setup" + ".exe";
1441#elif defined(Q_OS_ANDROID)
1442 szFileName = qApp->applicationName().toLower() + "_" + m_szCurrentVersion + ".apk";
1443#elif defined(Q_OS_LINUX)
1444 QFileInfo f(qApp->applicationFilePath());
1445 if(f.suffix().compare("AppImage", Qt::CaseInsensitive))
1446 {
1447 QString szVersion = m_szCurrentVersion;
1448 szVersion.replace("v", "", Qt::CaseInsensitive);
1449 szFileName = qApp->applicationName().toLower()
1450 + "_" + szVersion + "_amd64.deb";
1451 } else {
1452 szFileName = qApp->applicationName()
1453 + "_" + m_szCurrentVersion + ".tar.gz";
1454 }
1455#endif
1456
1457 QString szUrl;
1458 szUrl = "https://github.com/KangLin/"
1459 + qApp->applicationName()
1460 + "/releases/download/"
1461 + m_szCurrentVersion + "/" + szFileName;
1462
1463 parser.addHelpOption();
1464 parser.addVersionOption();
1465
1466 QCommandLineOption oFile(QStringList() << "f" << "file",
1467 tr("Configure file name"),
1468 "Configure file name",
1469 "update.json");
1470 parser.addOption(oFile);
1471 QCommandLineOption oFileOuputContent(QStringList() << "foc" << "file-output-content",
1472 tr("Configure file output content:") + "\n"
1473 + QString::number(static_cast<int>(CONFIG_TYPE::VERSION)) + tr(": content is version") + "\n"
1474 + QString::number(static_cast<int>(CONFIG_TYPE::FILE)) + tr(": content is file") + "\n"
1475 + QString::number(static_cast<int>(CONFIG_TYPE::VERSION_FILE)) + tr(": content is version and file"),
1476 "Configure file output content",
1477 QString::number(static_cast<int>(CONFIG_TYPE::VERSION_FILE)));
1478 parser.addOption(oFileOuputContent);
1479 QCommandLineOption oPackageVersion(QStringList() << "pv" << "package-version",
1480 tr("Package version"),
1481 "Package version",
1482 m_szCurrentVersion);
1483 parser.addOption(oPackageVersion);
1484 QCommandLineOption oTime(QStringList() << "t" << "time",
1485 tr("Time"),
1486 "Time",
1487 QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"));
1488 parser.addOption(oTime);
1489 QCommandLineOption oInfo(QStringList() << "i" << "info",
1490 tr("Information"),
1491 "Information",
1492 qApp->applicationName() + " " + m_szCurrentVersion);
1493 parser.addOption(oInfo);
1494
1495 QCommandLineOption oSystem(QStringList() << "s" << "system",
1496 tr("Operating system"),
1497 "Operating system",
1498 QSysInfo::productType());
1499 parser.addOption(oSystem);
1500 QCommandLineOption oArch(QStringList() << "a" << "arch",
1501 tr("Architecture"),
1502 "Architecture",
1503 QSysInfo::buildCpuArchitecture());
1504 parser.addOption(oArch);
1505 QCommandLineOption oMd5(QStringList() << "c" << "md5",
1506 tr("MD5 checksum"),
1507 "MD5 checksum");
1508 parser.addOption(oMd5);
1509 QCommandLineOption oPackageFile(QStringList() << "p" << "pf" << "package-file",
1510 tr("Package file, Is used to calculate md5sum"),
1511 "Package file"
1512 );
1513 parser.addOption(oPackageFile);
1514 QCommandLineOption oFileName(QStringList() << "n" << "file-name",
1515 tr("File name"),
1516 "File name"
1517 );
1518 parser.addOption(oFileName);
1519 QCommandLineOption oUrl(QStringList() << "u" << "urls",
1520 tr("Package download urls"),
1521 "Download urls",
1522 szUrl);
1523 parser.addOption(oUrl);
1524 QString szHome = "https://github.com/KangLin/" + qApp->applicationName();
1525 QCommandLineOption oUrlHome("home",
1526 tr("Project home url"),
1527 "Project home url",
1528 szHome);
1529 parser.addOption(oUrlHome);
1530 QCommandLineOption oMin(QStringList() << "m" << "min" << "min-update-version",
1531 tr("Min update version"),
1532 "Min update version",
1533 m_szCurrentVersion);
1534 parser.addOption(oMin);
1535 QCommandLineOption oForce(QStringList() << "force",
1536 tr("Set force flag"),
1537 "Force flag",
1538 "false");
1539 parser.addOption(oForce);
1540
1541 if(!parser.parse(QApplication::arguments())) {
1542 qDebug(log) << "parser.parse fail" << parser.errorText()
1543 << qApp->arguments();
1544 }
1545
1546 szFile = parser.value(oFile);
1547 if(szFile.isEmpty())
1548 qDebug(log) << "File is empty";
1549
1550 type = static_cast<CONFIG_TYPE>(parser.value(oFileOuputContent).toInt());
1551 qDebug(log) << "File content is:" << (int)type;
1552
1553 info.version.szVerion = parser.value(oPackageVersion);
1554 info.version.szMinUpdateVersion = parser.value(oMin);
1555 info.version.szTime = parser.value(oTime);
1556 info.version.szInfomation = parser.value(oInfo);
1557 info.version.szHome = parser.value(oUrlHome);
1558 QString szForce = parser.value(oForce).trimmed();
1559 if(szForce.compare("true", Qt::CaseInsensitive))
1560 info.version.bForce = false;
1561 else
1562 info.version.bForce = true;
1563
1564 CONFIG_FILE file;
1565 file.szSystem = parser.value(oSystem);
1566 file.szArchitecture = parser.value(oArch);
1567 file.szMd5sum = parser.value(oMd5);
1568 file.szFileName = parser.value(oFileName);
1569
1570 QString szPackageFile = parser.value(oPackageFile);
1571 if(!szPackageFile.isEmpty()) {
1572 QFileInfo fi(szPackageFile);
1573 if(file.szFileName.isEmpty())
1574 file.szFileName = fi.fileName();
1575 if(file.szMd5sum.isEmpty())
1576 {
1577 //计算包的 MD5 和
1578 QCryptographicHash md5sum(QCryptographicHash::Md5);
1579 QFile app(szPackageFile);
1580 if(app.open(QIODevice::ReadOnly))
1581 {
1582 if(md5sum.addData(&app))
1583 {
1584 file.szMd5sum = md5sum.result().toHex();
1585 }
1586 app.close();
1587 } else {
1588 qCritical(log) << "Don't open package file:" << szPackageFile;
1589 }
1590 }
1591 }
1592
1593 if(file.szMd5sum.isEmpty())
1594 qWarning(log) << "Md5 is empty. please set -c or --md5 or -p";
1595
1596 /* 注意:这里要放在包文件后。
1597 * 优先级:
1598 * 1. -n 参数设置
1599 * 2. 从包文件中提取
1600 * 3. 默认值
1601 */
1602 if(file.szFileName.isEmpty())
1603 file.szFileName = szFileName;
1604
1605 QString szUrls = parser.value(oUrl);
1606 foreach(auto u, szUrls.split(QRegularExpression("[;,]")))
1607 {
1608 file.urls.push_back(QUrl(u));
1609 }
1610
1611 info.files.append(file);
1612
1613 return 0;
1614}
1615
1616void CFrmUpdater::showEvent(QShowEvent *event)
1617{
1618 Q_UNUSED(event)
1619 if(!m_StateMachine.isRunning())
1620 m_StateMachine.start();
1621}
1622
1623void CFrmUpdater::slotShowWindow(QSystemTrayIcon::ActivationReason reason)
1624{
1625 Q_UNUSED(reason)
1626#if defined(Q_OS_ANDROID)
1627 showMaximized();
1628#else
1629 show();
1630#endif
1631 m_TrayIcon.hide();
1632}
1633
1634bool CFrmUpdater::CheckPrompt(const QString &szVersion)
1635{
1636 QSettings set(RabbitCommon::CDir::Instance()->GetFileUserConfigure(),
1637 QSettings::IniFormat);
1638 QString version = set.value("Updater/Version", m_szCurrentVersion).toString();
1639 set.setValue("Updater/Version", szVersion);
1640 int nRet = CompareVersion(szVersion, version);
1641 if (nRet > 0)
1642 return true;
1643 else if(nRet == 0)
1644 return !ui->cbPrompt->isChecked();
1645 return false;
1646}
1647
1648void CFrmUpdater::on_cbPrompt_clicked(bool checked)
1649{
1650 QSettings set(RabbitCommon::CDir::Instance()->GetFileUserConfigure(),
1651 QSettings::IniFormat);
1652 set.setValue("Updater/Prompt", checked);
1653}
1654
1655void CFrmUpdater::on_cbHomePage_clicked(bool checked)
1656{
1657 QSettings set(RabbitCommon::CDir::Instance()->GetFileUserConfigure(),
1658 QSettings::IniFormat);
1659 set.setValue("Updater/ShowHomePage", checked);
1660}
1661
1663{
1664 m_InstallAutoStartupType = bAutoStart;
1665 return 0;
1666}
Updater.
Definition FrmUpdater.h:70
CFrmUpdater(QVector< QUrl > urls=QVector< QUrl >(), QWidget *parent=nullptr)
CFrmUpdater.
int GenerateUpdateJson()
Generate update json configure file.
int CheckRedirectConfigFile()
检查重定向配置文件
int GetConfigFromCommandLine(QCommandLineParser &parser, QString &szFile, CONFIG_INFO &info, CONFIG_TYPE &type)
Get configure from command-line.
bool IsDownLoad()
Check file is exist.
int InitStateMachine()
Initialization state machine.
int GenerateJsonFile(const QString &szFile, const CONFIG_INFO &info, CONFIG_TYPE type)
Generate Json File.
Q_DECL_DEPRECATED int GenerateUpdateXml()
Update XML file used only to generate programs.
int SetTitle(QImage icon=QImage(), const QString &szTitle=QString())
SetTitle.
int CompareVersion(const QString &newVersion, const QString &currentVersion)
CFrmUpdater::CompareVersion.
int SetInstallAutoStartup(bool bAutoStart=true)
Set install and automation startup.
int GetConfigFromFile(const QString &szFile, CONFIG_INFO &conf)
json 格式:
int GetRedirectFromFile(const QString &szFile, QVector< CONFIG_REDIRECT > &conf)
Get redirect configure from file.
int CheckUpdateConfigFile()
检查更新配置文件
Download the same file from multiple URLs.
Definition Download.h:45
static bool executeByRoot(const QString &program, const QStringList &arguments=QStringList())
executeByRoot: Run with administrator privileges