149 lines
5.2 KiB
C++
149 lines
5.2 KiB
C++
#include <QXmlStreamReader>
|
|
#include <QGuiApplication>
|
|
#include "updates_checker.h"
|
|
#include "version.h"
|
|
|
|
UpdatesChecker::UpdatesChecker()
|
|
{
|
|
connect(&m_networkAccessManager, &QNetworkAccessManager::finished, this, &UpdatesChecker::downloadFinished);
|
|
}
|
|
|
|
void UpdatesChecker::start()
|
|
{
|
|
QUrl url(APP_UPDATES_CHECKER_URL);
|
|
QNetworkRequest request(url);
|
|
m_networkAccessManager.get(request);
|
|
}
|
|
|
|
const QString &UpdatesChecker::message() const
|
|
{
|
|
return m_message;
|
|
}
|
|
|
|
bool UpdatesChecker::isLatest() const
|
|
{
|
|
return m_isLatest;
|
|
}
|
|
|
|
bool UpdatesChecker::hasError() const
|
|
{
|
|
return m_hasError;
|
|
}
|
|
|
|
bool UpdatesChecker::parseUpdateInfoXml(const QByteArray &updateInfoXml, std::vector<UpdateItem> *updateItems)
|
|
{
|
|
std::vector<QString> elementNameStack;
|
|
QXmlStreamReader reader(updateInfoXml);
|
|
while (!reader.atEnd()) {
|
|
reader.readNext();
|
|
if (!reader.isStartElement() && !reader.isEndElement()) {
|
|
if (!reader.name().toString().isEmpty())
|
|
qDebug() << "Skip xml element:" << reader.name().toString() << " tokenType:" << reader.tokenType();
|
|
continue;
|
|
}
|
|
QString baseName = reader.name().toString();
|
|
if (reader.isStartElement()) {
|
|
elementNameStack.push_back(baseName);
|
|
if (elementNameStack.size() > 10) {
|
|
qDebug() << "Invalid xml, element name stack exceed limits";
|
|
return false;
|
|
}
|
|
}
|
|
QStringList nameItems;
|
|
for (const auto &nameItem: elementNameStack) {
|
|
nameItems.append(nameItem);
|
|
}
|
|
QString fullName = nameItems.join(".");
|
|
if (reader.isEndElement())
|
|
elementNameStack.pop_back();
|
|
if (reader.isStartElement()) {
|
|
if (fullName == "updates.update") {
|
|
UpdateItem updateItem;
|
|
updateItem.forTags = reader.attributes().value("for").toString().toLower();
|
|
updateItem.version = reader.attributes().value("version").toString();
|
|
updateItem.humanVersion = reader.attributes().value("humanVersion").toString();
|
|
updateItem.descriptionUrl = reader.attributes().value("descriptionUrl").toString();
|
|
if (!updateItem.forTags.isEmpty() &&
|
|
!updateItem.version.isEmpty() &&
|
|
!updateItem.humanVersion.isEmpty() &&
|
|
!updateItem.descriptionUrl.isEmpty()) {
|
|
if (updateItems->size() >= 100)
|
|
return false;
|
|
updateItem.forTags = "," + updateItem.forTags + ",";
|
|
updateItems->push_back(updateItem);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool UpdatesChecker::isVersionLessThan(const QString &version, const QString &compareWith)
|
|
{
|
|
auto versionTokens = version.split(".");
|
|
auto compareWithTokens = compareWith.split(".");
|
|
if (versionTokens.size() > 4) {
|
|
return false;
|
|
}
|
|
while (compareWithTokens.size() < 4)
|
|
compareWithTokens.push_back("0");
|
|
if (compareWithTokens.size() > 4) {
|
|
return false;
|
|
}
|
|
while (compareWithTokens.size() < 4)
|
|
compareWithTokens.push_back("0");
|
|
for (size_t i = 0; i < 4; ++i) {
|
|
int left = versionTokens[i].toInt();
|
|
int right = compareWithTokens[i].toInt();
|
|
if (left > right)
|
|
return false;
|
|
else if (left < right)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
const UpdatesChecker::UpdateItem &UpdatesChecker::matchedUpdateItem() const
|
|
{
|
|
return m_matchedUpdateItem;
|
|
}
|
|
|
|
void UpdatesChecker::downloadFinished(QNetworkReply *reply)
|
|
{
|
|
if (reply->error()) {
|
|
qDebug() << "Download update info failed:" << qPrintable(reply->errorString());
|
|
m_message = tr("Fetch update info failed, please retry later");
|
|
} else {
|
|
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
|
if (200 != statusCode) {
|
|
qDebug() << "Download update info failed, statusCode:" << statusCode;
|
|
m_message = tr("Fetch update info failed, please retry later");
|
|
} else {
|
|
std::vector<UpdateItem> updateItems;
|
|
if (!parseUpdateInfoXml(reply->readAll(), &updateItems)) {
|
|
m_message = tr("Fetch update info failed, please retry later");
|
|
} else {
|
|
m_isLatest = true;
|
|
m_hasError = false;
|
|
m_message = tr("%1 %2 is currently the newest version available").arg(APP_NAME).arg(APP_HUMAN_VER);
|
|
QString platform = QString(APP_PLATFORM).toLower();
|
|
if (!platform.isEmpty()) {
|
|
platform = "," + platform + ",";
|
|
for (const auto &it: updateItems) {
|
|
if (-1 == it.forTags.indexOf(platform))
|
|
continue;
|
|
if (isVersionLessThan(APP_VER, it.version)) {
|
|
m_isLatest = false;
|
|
m_message = tr("An update is available: %1 %2").arg(APP_NAME).arg(it.humanVersion);
|
|
m_matchedUpdateItem = it;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
reply->deleteLater();
|
|
emit finished();
|
|
}
|