From 872c57068f22a25580a99504f216c30993b4b2a1 Mon Sep 17 00:00:00 2001 From: saturneric Date: Sun, 1 Jun 2025 01:18:00 +0200 Subject: feat(ver_check): add bktus version check support - implement BKTUSVersionCheckTask for bktus.com version checking - refactor version checking logic into Utils.cpp - update version checking module to support multiple sources - improve version status display messages --- src/m_ver_check/BKTUSVersionCheckTask.cpp | 268 +++++++++++++++++++++++++++++ src/m_ver_check/BKTUSVersionCheckTask.h | 101 +++++++++++ src/m_ver_check/CMakeLists.txt | 2 +- src/m_ver_check/GitHubVersionCheckTask.cpp | 180 +++++++++++++++++++ src/m_ver_check/GitHubVersionCheckTask.h | 101 +++++++++++ src/m_ver_check/SoftwareVersion.cpp | 9 +- src/m_ver_check/SoftwareVersion.h | 15 +- src/m_ver_check/UpdateTab.cpp | 57 +++--- src/m_ver_check/Utils.cpp | 75 ++++++++ src/m_ver_check/Utils.h | 33 ++++ src/m_ver_check/VersionCheckTask.cpp | 239 ------------------------- src/m_ver_check/VersionCheckTask.h | 106 ------------ src/m_ver_check/VersionCheckingModule.cpp | 29 +++- 13 files changed, 819 insertions(+), 396 deletions(-) create mode 100644 src/m_ver_check/BKTUSVersionCheckTask.cpp create mode 100644 src/m_ver_check/BKTUSVersionCheckTask.h create mode 100644 src/m_ver_check/GitHubVersionCheckTask.cpp create mode 100644 src/m_ver_check/GitHubVersionCheckTask.h create mode 100644 src/m_ver_check/Utils.cpp create mode 100644 src/m_ver_check/Utils.h delete mode 100644 src/m_ver_check/VersionCheckTask.cpp delete mode 100644 src/m_ver_check/VersionCheckTask.h diff --git a/src/m_ver_check/BKTUSVersionCheckTask.cpp b/src/m_ver_check/BKTUSVersionCheckTask.cpp new file mode 100644 index 0000000..dc9f404 --- /dev/null +++ b/src/m_ver_check/BKTUSVersionCheckTask.cpp @@ -0,0 +1,268 @@ +/** + * Copyright (C) 2021-2024 Saturneric + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see . + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "BKTUSVersionCheckTask.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include "GFModuleCommonUtils.hpp" +#include "SoftwareVersion.h" +#include "Utils.h" +#include "VersionCheckingModule.h" + +BKTUSVersionCheckTask::BKTUSVersionCheckTask() + : network_manager_(new QNetworkAccessManager(this)), + current_version_(GFProjectVersion()) { + qRegisterMetaType("SoftwareVersion"); + version_meta_data_.current_version = current_version_; + version_meta_data_.local_commit_hash = GFProjectGitCommitHash(); +} + +auto BKTUSVersionCheckTask::Run() -> int { + QString base_url = ""; + QList urls = { + {"https://ftp.bktus.com/GpgFrontend/LATEST"}, + {"https://git.bktus.com/GpgFrontend/GpgFrontend/atom/?h=" + + current_version_}, + {"https://git.bktus.com/GpgFrontend/GpgFrontend/atom/?id=" + + version_meta_data_.local_commit_hash}, + }; + + connect(network_manager_, &QNetworkAccessManager::finished, this, + &BKTUSVersionCheckTask::slot_parse_reply); + + for (const QUrl& url : urls) { + QNetworkRequest request(url); + request.setHeader(QNetworkRequest::UserAgentHeader, + GFHttpRequestUserAgent()); + QNetworkReply* reply = network_manager_->get(request); + replies_.append(reply); + } + + return 0; +} + +void BKTUSVersionCheckTask::slot_parse_reply(QNetworkReply* reply) { + if (reply->error() == QNetworkReply::NoError) { + FLOG_DEBUG("get reply from url: %1", reply->url().toString()); + switch (replies_.indexOf(reply)) { + case 0: + slot_parse_latest_version_info(reply); + break; + case 1: + slot_parse_current_tag_info(reply); + break; + case 2: + slot_parse_current_commit_hash_info(reply); + break; + default: + break; + } + } else { + FLOG_DEBUG("get reply from url: %1, error: %2 %3", reply->url().toString(), + reply->errorString(), reply->readAll()); + } + + replies_.removeAll(reply); + reply->deleteLater(); + + if (replies_.isEmpty()) { + FillGrtWithVersionInfo(version_meta_data_); + emit SignalUpgradeVersion(version_meta_data_); + } +} + +void BKTUSVersionCheckTask::slot_parse_latest_version_info( + QNetworkReply* reply) { + if (reply == nullptr || reply->error() != QNetworkReply::NoError) { + return; + } + + auto reply_bytes = reply->readAll(); + auto latest_reply_json = QJsonDocument::fromJson(reply_bytes); + + if (!latest_reply_json.isObject()) { + FLOG_WARN("cannot parse data from bktus: %1", reply_bytes); + return; + } + + QString latest_version = latest_reply_json["version"].toString(); + FLOG_DEBUG("raw tag name from bktus: %1", latest_version); + + QRegularExpression re(R"(^[vV](\d+\.)?(\d+\.)?(\*|\d+))"); + auto version_match = re.match(latest_version); + if (version_match.hasMatch()) { + latest_version = version_match.captured(0); + } else { + latest_version = ""; + FLOG_WARN("the raw release name from bktus: %1 cannot match regex rules", + latest_version); + } + + auto publish_date = latest_reply_json["release_date"].toString(); + auto release_note = latest_reply_json["release_notes"].toString(); + + version_meta_data_.latest_version = latest_version; + version_meta_data_.publish_date = publish_date; + version_meta_data_.release_note = release_note; +} + +void BKTUSVersionCheckTask::slot_parse_current_tag_info(QNetworkReply* reply) { + if (reply == nullptr || reply->error() != QNetworkReply::NoError) return; + + QVariant status_code = + reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); + int status = status_code.toInt(); + + if (status != 200) { + FLOG_WARN("http status code from git.bktus.com is not 200: %1", status); + return; + } + + auto reply_bytes = reply->readAll(); + + QDomDocument doc; + QString err_msg; + int err_line = 0; + int err_column = 0; + QString xml_text = QString::fromUtf8(reply_bytes); + bool ok = doc.setContent(xml_text, &err_msg, &err_line, &err_column); + if (!ok) { + FLOG_WARN("xml parse failed: %1, line: %2, column: %3", err_msg, err_line, + err_column); + return; + } + + auto entries = doc.elementsByTagName("entry"); + + if (entries.size() == 0) { + FLOG_WARN("no xml entry of current version: %1", current_version_); + return; + } + + QDomElement entry_elem = entries.at(0).toElement(); + if (entry_elem.isNull()) { + FLOG_WARN("first xml entry of current version: %1 is null", + current_version_); + version_meta_data_.current_commit_hash_publish_in_remote = false; + return; + } + + auto title_elem = entry_elem.firstChildElement("title"); + auto id_elem = entry_elem.firstChildElement("id"); + auto published_elem = entry_elem.firstChildElement("published"); + + if (title_elem.isNull() || id_elem.isNull() || published_elem.isNull()) { + FLOG_WARN("illegal xml entry of structure of version: %1", + current_version_); + version_meta_data_.current_commit_hash_publish_in_remote = false; + return; + } + + auto title_text = title_elem.text(); + auto id_text = id_elem.text(); + auto published_text = published_elem.text(); + + FLOG_DEBUG("got tag info from bktus: %1, %2, %3", title_text, id_text, + published_text); + + const auto& sha = id_text; + version_meta_data_.remote_commit_hash_by_tag = sha.trimmed(); + version_meta_data_.current_version_publish_in_remote = true; +} + +void BKTUSVersionCheckTask::slot_parse_current_commit_hash_info( + QNetworkReply* reply) { + if (reply == nullptr || reply->error() != QNetworkReply::NoError) { + return; + } + + QVariant status_code = + reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); + int status = status_code.toInt(); + + if (status != 200) { + FLOG_WARN("http status code from git.bktus.com is not 200: %1", status); + return; + } + + auto reply_bytes = reply->readAll(); + + QDomDocument doc; + QString err_msg; + int err_line = 0; + int err_column = 0; + QString xml_text = QString::fromUtf8(reply_bytes); + bool ok = doc.setContent(xml_text, &err_msg, &err_line, &err_column); + if (!ok) { + FLOG_WARN("xml parse failed: %1, line: %2, column: %3", err_msg, err_line, + err_column); + return; + } + + auto entries = doc.elementsByTagName("entry"); + + if (entries.size() == 0) { + FLOG_WARN("no xml entry of current version: %1", current_version_); + return; + } + + QDomElement entry_elem = entries.at(0).toElement(); + if (entry_elem.isNull()) { + FLOG_WARN("first xml entry of current version: %1 is null", + current_version_); + return; + } + + auto title_elem = entry_elem.firstChildElement("title"); + auto id_elem = entry_elem.firstChildElement("id"); + auto published_elem = entry_elem.firstChildElement("published"); + + if (title_elem.isNull() || id_elem.isNull() || published_elem.isNull()) { + FLOG_WARN("illegal xml entry of structure of version: %1", + current_version_); + return; + } + + auto title_text = title_elem.text(); + auto id_text = id_elem.text(); + auto published_text = published_elem.text(); + + FLOG_DEBUG("got commit info from bktus: %1, %2, %3", title_text, id_text, + published_text); + + version_meta_data_.current_commit_hash_publish_in_remote = + id_text.trimmed() == version_meta_data_.local_commit_hash.trimmed(); +} diff --git a/src/m_ver_check/BKTUSVersionCheckTask.h b/src/m_ver_check/BKTUSVersionCheckTask.h new file mode 100644 index 0000000..df2cc59 --- /dev/null +++ b/src/m_ver_check/BKTUSVersionCheckTask.h @@ -0,0 +1,101 @@ +/** + * Copyright (C) 2021-2024 Saturneric + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see . + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include + +#include "SoftwareVersion.h" + +class QNetworkReply; +class QNetworkAccessManager; + +/** + * @brief + * + */ +class BKTUSVersionCheckTask : public QObject { + Q_OBJECT + public: + /** + * @brief Construct a new Version Check Thread object + * + */ + BKTUSVersionCheckTask(); + + /** + * @brief + * + * @return int + */ + auto Run() -> int; + + signals: + + /** + * @brief + * + * @param version + */ + void SignalUpgradeVersion(SoftwareVersion version); + + private slots: + + /** + * @brief + * + */ + void slot_parse_reply(QNetworkReply* reply); + + /** + * @brief + * + * @param reply + */ + void slot_parse_latest_version_info(QNetworkReply* reply); + + /** + * @brief + * + * @param reply + */ + void slot_parse_current_tag_info(QNetworkReply* reply); + + /** + * @brief + * + * @param reply + */ + void slot_parse_current_commit_hash_info(QNetworkReply* reply); + + private: + QList replies_; ///< + QNetworkAccessManager* network_manager_; ///< + QString current_version_; ///< + SoftwareVersion version_meta_data_; +}; diff --git a/src/m_ver_check/CMakeLists.txt b/src/m_ver_check/CMakeLists.txt index e6cb54e..2da23c8 100644 --- a/src/m_ver_check/CMakeLists.txt +++ b/src/m_ver_check/CMakeLists.txt @@ -32,7 +32,7 @@ aux_source_directory(. INTEGRATED_MODULE_SOURCE) register_module(ver_check MODULE_TARGET ${INTEGRATED_MODULE_SOURCE}) # link qt -target_link_libraries(${MODULE_TARGET} PUBLIC Qt::Core Qt::Network Qt::Widgets) +target_link_libraries(${MODULE_TARGET} PUBLIC Qt::Core Qt::Network Qt::Widgets Qt::Xml) # ui set(CMAKE_AUTOUIC_SEARCH_PATHS ${CMAKE_AUTOUIC_SEARCH_PATHS} ${CMAKE_CURRENT_SOURCE_DIR}/ui) diff --git a/src/m_ver_check/GitHubVersionCheckTask.cpp b/src/m_ver_check/GitHubVersionCheckTask.cpp new file mode 100644 index 0000000..3a1419a --- /dev/null +++ b/src/m_ver_check/GitHubVersionCheckTask.cpp @@ -0,0 +1,180 @@ +/** + * Copyright (C) 2021-2024 Saturneric + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see . + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "GitHubVersionCheckTask.h" + +#include +#include +#include +#include + +#include +#include + +#include "GFModuleCommonUtils.hpp" +#include "SoftwareVersion.h" +#include "Utils.h" +#include "VersionCheckingModule.h" + +GitHubVersionCheckTask::GitHubVersionCheckTask() + : network_manager_(new QNetworkAccessManager(this)), + current_version_(GFProjectVersion()) { + qRegisterMetaType("SoftwareVersion"); + version_meta_data_.current_version = current_version_; + version_meta_data_.local_commit_hash = GFProjectGitCommitHash(); +} + +auto GitHubVersionCheckTask::Run() -> int { + QString base_url = "https://api.github.com/repos/saturneric/gpgfrontend"; + QList urls = { + {base_url + "/releases/latest"}, + {base_url + "/releases/tags/" + current_version_}, + {base_url + "/git/ref/tags/" + current_version_}, + }; + + connect(network_manager_, &QNetworkAccessManager::finished, this, + &GitHubVersionCheckTask::slot_parse_reply); + + for (const QUrl& url : urls) { + QNetworkRequest request(url); + request.setHeader(QNetworkRequest::UserAgentHeader, + GFHttpRequestUserAgent()); + QNetworkReply* reply = network_manager_->get(request); + replies_.append(reply); + } + + return 0; +} + +void GitHubVersionCheckTask::slot_parse_reply(QNetworkReply* reply) { + if (reply->error() == QNetworkReply::NoError) { + FLOG_DEBUG("get reply from url: %1", reply->url().toString()); + switch (replies_.indexOf(reply)) { + case 0: + slot_parse_latest_version_info(reply); + break; + case 1: + slot_parse_current_version_info(reply); + break; + case 2: + slot_parse_current_tag_info(reply); + break; + default: + break; + } + } else { + FLOG_DEBUG("get reply from url: %1, error: %2 %3", reply->url().toString(), + reply->errorString(), reply->readAll()); + } + + replies_.removeAll(reply); + reply->deleteLater(); + + if (replies_.isEmpty()) { + FillGrtWithVersionInfo(version_meta_data_); + emit SignalUpgradeVersion(version_meta_data_); + } +} + +void GitHubVersionCheckTask::slot_parse_latest_version_info( + QNetworkReply* reply) { + if (reply == nullptr || reply->error() != QNetworkReply::NoError) { + return; + } + + auto reply_bytes = reply->readAll(); + auto latest_reply_json = QJsonDocument::fromJson(reply_bytes); + + if (!latest_reply_json.isObject()) { + FLOG_WARN("cannot parse data from github: %1", reply_bytes); + return; + } + + QString latest_version = latest_reply_json["tag_name"].toString(); + FLOG_DEBUG("raw tag name from github: %1", latest_version); + + QRegularExpression re(R"(^[vV](\d+\.)?(\d+\.)?(\*|\d+))"); + auto version_match = re.match(latest_version); + if (version_match.hasMatch()) { + latest_version = version_match.captured(0); + } else { + latest_version = ""; + FLOG_WARN("the raw tag name from github: %1 cannot match regex rules", + latest_version); + } + + auto publish_date = latest_reply_json["published_at"].toString(); + auto release_note = latest_reply_json["body"].toString(); + + version_meta_data_.latest_version = latest_version; + version_meta_data_.publish_date = publish_date; + version_meta_data_.release_note = release_note; +} + +void GitHubVersionCheckTask::slot_parse_current_version_info( + QNetworkReply* reply) { + if (reply == nullptr || reply->error() != QNetworkReply::NoError) return; + + auto reply_bytes = reply->readAll(); + auto current_reply_json = QJsonDocument::fromJson(reply_bytes); + + if (!current_reply_json.isObject()) { + FLOG_WARN("cannot parse data from github: %1", reply_bytes); + return; + } + + version_meta_data_.current_version_publish_in_remote = true; +} + +void GitHubVersionCheckTask::slot_parse_current_tag_info(QNetworkReply* reply) { + if (reply == nullptr || reply->error() != QNetworkReply::NoError) { + version_meta_data_.current_version_publish_in_remote = false; + return; + } + + version_meta_data_.current_version_publish_in_remote = true; + auto reply_bytes = reply->readAll(); + auto current_reply_json = QJsonDocument::fromJson(reply_bytes); + + if (!current_reply_json.isObject()) { + FLOG_WARN("cannot parse data from github: %1", reply_bytes); + return; + } + + auto object = current_reply_json["object"].toObject(); + if (object["type"].toString() != "commit") { + FLOG_WARN("remote tag: %1 is not a ref: %2", + version_meta_data_.current_version, object["type"].toString()); + return; + } + + auto sha = object["sha"].toString(); + version_meta_data_.remote_commit_hash_by_tag = sha.trimmed(); + FLOG_DEBUG("got remote commit hash: %1", + version_meta_data_.remote_commit_hash_by_tag); +} diff --git a/src/m_ver_check/GitHubVersionCheckTask.h b/src/m_ver_check/GitHubVersionCheckTask.h new file mode 100644 index 0000000..c77f8fa --- /dev/null +++ b/src/m_ver_check/GitHubVersionCheckTask.h @@ -0,0 +1,101 @@ +/** + * Copyright (C) 2021-2024 Saturneric + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see . + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include + +#include "SoftwareVersion.h" + +class QNetworkReply; +class QNetworkAccessManager; + +/** + * @brief + * + */ +class GitHubVersionCheckTask : public QObject { + Q_OBJECT + public: + /** + * @brief Construct a new Version Check Thread object + * + */ + GitHubVersionCheckTask(); + + /** + * @brief + * + * @return int + */ + auto Run() -> int; + + signals: + + /** + * @brief + * + * @param version + */ + void SignalUpgradeVersion(SoftwareVersion version); + + private slots: + + /** + * @brief + * + */ + void slot_parse_reply(QNetworkReply* reply); + + /** + * @brief + * + * @param reply + */ + void slot_parse_latest_version_info(QNetworkReply* reply); + + /** + * @brief + * + * @param reply + */ + void slot_parse_current_version_info(QNetworkReply* reply); + + /** + * @brief + * + * @param reply + */ + void slot_parse_current_tag_info(QNetworkReply* reply); + + private: + QList replies_; ///< + QNetworkAccessManager* network_manager_; ///< + QString current_version_; ///< + SoftwareVersion version_meta_data_; +}; diff --git a/src/m_ver_check/SoftwareVersion.cpp b/src/m_ver_check/SoftwareVersion.cpp index 04e3556..9f53791 100644 --- a/src/m_ver_check/SoftwareVersion.cpp +++ b/src/m_ver_check/SoftwareVersion.cpp @@ -44,18 +44,13 @@ auto SoftwareVersion::NeedUpgrade() const -> bool { GFModuleStrDup(current_version.toUtf8()), GFModuleStrDup(latest_version.toUtf8())))); - FLOG_DEBUG("remote latest version: %1, pre-release: %2, draft: %3", - latest_version, latest_prerelease_version_from_remote, - latest_draft_from_remote); - return !latest_version.isEmpty() && !latest_prerelease_version_from_remote && - !latest_draft_from_remote && + return !latest_version.isEmpty() && GFCompareSoftwareVersion(GFModuleStrDup(current_version.toUtf8()), GFModuleStrDup(latest_version.toUtf8())) < 0; } auto SoftwareVersion::VersionWithdrawn() const -> bool { - return !latest_version.isEmpty() && !current_version_publish_in_remote && - current_version_is_a_prerelease && !current_version_is_drafted; + return !latest_version.isEmpty() && !current_version_publish_in_remote; } auto SoftwareVersion::CurrentVersionReleased() const -> bool { diff --git a/src/m_ver_check/SoftwareVersion.h b/src/m_ver_check/SoftwareVersion.h index f66c0dd..ed89964 100644 --- a/src/m_ver_check/SoftwareVersion.h +++ b/src/m_ver_check/SoftwareVersion.h @@ -35,15 +35,14 @@ * */ struct SoftwareVersion { - QString latest_version; ///< - QString current_version; ///< - bool latest_prerelease_version_from_remote = false; ///< - bool latest_draft_from_remote = false; ///< - bool current_version_is_a_prerelease = false; ///< - bool current_version_is_drafted = false; ///< + QString latest_version; ///< + QString current_version; ///< + bool current_version_publish_in_remote = false; ///< - QString publish_date; ///< - QString release_note; ///< + bool current_commit_hash_publish_in_remote = false; ///< + + QString publish_date; ///< + QString release_note; ///< QString remote_commit_hash_by_tag; QString local_commit_hash; diff --git a/src/m_ver_check/UpdateTab.cpp b/src/m_ver_check/UpdateTab.cpp index a835fb1..34951e5 100644 --- a/src/m_ver_check/UpdateTab.cpp +++ b/src/m_ver_check/UpdateTab.cpp @@ -31,7 +31,7 @@ #include "GFModuleCommonUtils.hpp" #include "GFSDKBasic.h" #include "GFSDKModule.h" -#include "VersionCheckTask.h" +#include "GitHubVersionCheckTask.h" #include "VersionCheckingModule.h" UpdateTab::UpdateTab(QWidget* parent) @@ -90,11 +90,12 @@ void UpdateTab::showEvent(QShowEvent* event) { GFGetModuleID(), GFModuleStrDup("version.loading_done"), 0); if (is_loading_done == 0) { - auto* task = new VersionCheckTask(); - QObject::connect( - task, &VersionCheckTask::SignalUpgradeVersion, QThread::currentThread(), - [this](const SoftwareVersion&) { slot_show_version_status(); }); - QObject::connect(task, &VersionCheckTask::SignalUpgradeVersion, task, + auto* task = new GitHubVersionCheckTask(); + QObject::connect(task, &GitHubVersionCheckTask::SignalUpgradeVersion, + QThread::currentThread(), [this](const SoftwareVersion&) { + slot_show_version_status(); + }); + QObject::connect(task, &GitHubVersionCheckTask::SignalUpgradeVersion, task, &QObject::deleteLater); task->Run(); @@ -132,16 +133,19 @@ void UpdateTab::slot_show_version_status() { auto is_need_upgrade = GFModuleRetrieveRTValueOrDefaultBool( GFGetModuleID(), GFModuleStrDup("version.need_upgrade"), 0); - auto is_current_a_withdrawn_version = GFModuleRetrieveRTValueOrDefaultBool( - GFGetModuleID(), GFModuleStrDup("version.current_a_withdrawn_version"), - 0); - - auto is_current_version_released = GFModuleRetrieveRTValueOrDefaultBool( - GFGetModuleID(), GFModuleStrDup("version.current_version_released"), 0); + auto is_current_version_publish_in_remote = + GFModuleRetrieveRTValueOrDefaultBool( + GFGetModuleID(), + GFModuleStrDup("version.current_version_publish_in_remote"), 0); auto is_git_commit_hash_mismatch = GFModuleRetrieveRTValueOrDefaultBool( GFGetModuleID(), GFModuleStrDup("version.git_commit_hash_mismatch"), 0); + auto is_current_commit_hash_publish_in_remote = + GFModuleRetrieveRTValueOrDefaultBool( + GFGetModuleID(), + GFModuleStrDup("version.current_commit_hash_publish_in_remote"), 0); + QString const latest_version = UDUP(GFModuleRetrieveRTValueOrDefault( GFGetModuleID(), GFModuleStrDup("version.latest_version"), GFModuleStrDup(""))); @@ -167,41 +171,42 @@ void UpdateTab::slot_show_version_status() { ""); upgrade_label_->show(); upgrade_info_box_->show(); - } else if (is_current_a_withdrawn_version != 0) { + } else if ((!latest_version.trimmed().isEmpty() && + is_current_version_publish_in_remote == 0)) { upgrade_label_->setText( "
" + - tr("This version has critical issues and has been withdrawn. Please " - "stop using it immediately.") + + tr("This version is either withdrawn due to critical issues or is an " + "unreleased build. " + "Please stop using it and download the latest stable version.") + "
" + tr("Click") + - " " + + " " + tr("here") + " " + tr("to download the latest stable version.") + "
"); upgrade_label_->show(); upgrade_info_box_->show(); - } else if (!latest_version.trimmed().isEmpty() && - is_current_version_released == 0) { + } else if (is_git_commit_hash_mismatch != 0 && GFIsCheckReleaseCommitHash()) { upgrade_label_->setText( "
" + - tr("This is an unreleased version, possibly a beta. If stability is " - "important to you, please avoid using this version.") + + tr("The current version's commit hash does not match the official " + "release. This may indicate a modified or unofficial build.") + "
" + tr("Click") + " " + - tr("here") + " " + tr("to download the latest stable version.") + + tr("here") + " " + + tr("to verify your installation or download the official version.") + "
"); upgrade_label_->show(); upgrade_info_box_->show(); - } else if (is_git_commit_hash_mismatch != 0 && !GFIsFlatpakENV()) { + } else if (is_current_commit_hash_publish_in_remote != 0) { upgrade_label_->setText( "
" + - tr("The current version's commit hash does not match the official " - "release. This may indicate a modified or unofficial build.") + + tr("The commit hash for this build was not found in the official " + "repository. This may indicate a modified or unofficial version.") + "
" + tr("Click") + " " + tr("here") + " " + - tr("to verify your installation or download the official version.") + + tr("to verify your installation or download the official build.") + "
"); upgrade_label_->show(); upgrade_info_box_->show(); diff --git a/src/m_ver_check/Utils.cpp b/src/m_ver_check/Utils.cpp new file mode 100644 index 0000000..4b45968 --- /dev/null +++ b/src/m_ver_check/Utils.cpp @@ -0,0 +1,75 @@ +/** + * Copyright (C) 2021-2024 Saturneric + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see . + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "Utils.h" + +#include +#include +#include + +#include "VersionCheckingModule.h" + +void FillGrtWithVersionInfo(const SoftwareVersion& version) { + GFModuleUpsertRTValue(GFGetModuleID(), + GFModuleStrDup("version.current_version"), + GFModuleStrDup(version.current_version.toUtf8())); + GFModuleUpsertRTValue(GFGetModuleID(), + GFModuleStrDup("version.latest_version"), + GFModuleStrDup(version.latest_version.toUtf8())); + GFModuleUpsertRTValue( + GFGetModuleID(), GFModuleStrDup("version.remote_commit_hash_by_tag"), + GFModuleStrDup(version.remote_commit_hash_by_tag.toUtf8())); + GFModuleUpsertRTValue(GFGetModuleID(), + GFModuleStrDup("version.local_commit_hash"), + GFModuleStrDup(version.local_commit_hash.toUtf8())); + + GFModuleUpsertRTValueBool( + GFGetModuleID(), + GFModuleStrDup("version.current_version_publish_in_remote"), + version.current_version_publish_in_remote ? 1 : 0); + GFModuleUpsertRTValueBool( + GFGetModuleID(), + GFModuleStrDup("version.current_commit_hash_publish_in_remote"), + version.current_commit_hash_publish_in_remote ? 1 : 0); + GFModuleUpsertRTValueBool(GFGetModuleID(), + GFModuleStrDup("version.need_upgrade"), + version.NeedUpgrade() ? 1 : 0); + GFModuleUpsertRTValueBool(GFGetModuleID(), + GFModuleStrDup("version.current_version_released"), + version.CurrentVersionReleased() ? 1 : 0); + GFModuleUpsertRTValueBool(GFGetModuleID(), + GFModuleStrDup("version.git_commit_hash_mismatch"), + version.GitCommitHashMismatch() ? 1 : 0); + + GFModuleUpsertRTValue(GFGetModuleID(), GFModuleStrDup("version.release_note"), + GFModuleStrDup(version.release_note.toUtf8())); + + GFModuleUpsertRTValueBool(GFGetModuleID(), + GFModuleStrDup("version.loading_done"), + version.IsInfoValid() ? 1 : 0); +} \ No newline at end of file diff --git a/src/m_ver_check/Utils.h b/src/m_ver_check/Utils.h new file mode 100644 index 0000000..954d7b7 --- /dev/null +++ b/src/m_ver_check/Utils.h @@ -0,0 +1,33 @@ +/** + * Copyright (C) 2021-2024 Saturneric + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see . + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "SoftwareVersion.h" + +void FillGrtWithVersionInfo(const SoftwareVersion& version); \ No newline at end of file diff --git a/src/m_ver_check/VersionCheckTask.cpp b/src/m_ver_check/VersionCheckTask.cpp deleted file mode 100644 index 271e932..0000000 --- a/src/m_ver_check/VersionCheckTask.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/** - * Copyright (C) 2021-2024 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GpgFrontend. If not, see . - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#include "VersionCheckTask.h" - -#include -#include -#include -#include - -#include -#include - -#include "GFModuleCommonUtils.hpp" -#include "SoftwareVersion.h" -#include "VersionCheckingModule.h" - -VersionCheckTask::VersionCheckTask() - : network_manager_(new QNetworkAccessManager(this)), - current_version_(GFProjectVersion()) { - qRegisterMetaType("SoftwareVersion"); - version_meta_data_.current_version = current_version_; - version_meta_data_.local_commit_hash = GFProjectGitCommitHash(); -} - -auto VersionCheckTask::Run() -> int { - QString base_url = "https://api.github.com/repos/saturneric/gpgfrontend"; - QList urls = { - {base_url + "/releases/latest"}, - {base_url + "/releases/tags/" + current_version_}, - {base_url + "/git/ref/tags/" + current_version_}, - }; - - connect(network_manager_, &QNetworkAccessManager::finished, this, - &VersionCheckTask::slot_parse_reply); - - for (const QUrl& url : urls) { - QNetworkRequest request(url); - request.setHeader(QNetworkRequest::UserAgentHeader, - GFHttpRequestUserAgent()); - QNetworkReply* reply = network_manager_->get(request); - replies_.append(reply); - } - - return 0; -} - -void VersionCheckTask::slot_parse_reply(QNetworkReply* reply) { - if (reply->error() == QNetworkReply::NoError) { - FLOG_DEBUG("get reply from url: %1", reply->url().toString()); - switch (replies_.indexOf(reply)) { - case 0: - slot_parse_latest_version_info(reply); - break; - case 1: - slot_parse_current_version_info(reply); - break; - case 2: - slot_parse_current_tag_info(reply); - break; - } - } else { - FLOG_DEBUG("get reply from url: %1, error: %2 %3", reply->url().toString(), - reply->errorString(), reply->readAll()); - } - - replies_.removeAll(reply); - reply->deleteLater(); - - if (replies_.isEmpty()) { - slot_fill_grt_with_version_info(version_meta_data_); - emit SignalUpgradeVersion(version_meta_data_); - } -} - -void VersionCheckTask::slot_parse_latest_version_info(QNetworkReply* reply) { - if (reply == nullptr || reply->error() != QNetworkReply::NoError) { - return; - } - - auto reply_bytes = reply->readAll(); - auto latest_reply_json = QJsonDocument::fromJson(reply_bytes); - - if (!latest_reply_json.isObject()) { - FLOG_WARN("cannot parse data from github: %1", reply_bytes); - return; - } - - QString latest_version = latest_reply_json["tag_name"].toString(); - FLOG_DEBUG("raw tag name from github: %1", latest_version); - - QRegularExpression re(R"(^[vV](\d+\.)?(\d+\.)?(\*|\d+))"); - auto version_match = re.match(latest_version); - if (version_match.hasMatch()) { - latest_version = version_match.captured(0); - } else { - latest_version = ""; - FLOG_WARN("the raw tag name from github: %1 cannot match regex rules", - latest_version); - } - - bool prerelease = latest_reply_json["prerelease"].toBool(); - bool draft = latest_reply_json["draft"].toBool(); - auto publish_date = latest_reply_json["published_at"].toString(); - auto release_note = latest_reply_json["body"].toString(); - version_meta_data_.latest_version = latest_version; - version_meta_data_.latest_prerelease_version_from_remote = prerelease; - version_meta_data_.latest_draft_from_remote = draft; - version_meta_data_.publish_date = publish_date; - version_meta_data_.release_note = release_note; -} - -void VersionCheckTask::slot_parse_current_version_info(QNetworkReply* reply) { - if (reply == nullptr || reply->error() != QNetworkReply::NoError) { - version_meta_data_.current_version_publish_in_remote = false; - return; - } - - version_meta_data_.current_version_publish_in_remote = true; - auto reply_bytes = reply->readAll(); - auto current_reply_json = QJsonDocument::fromJson(reply_bytes); - - if (!current_reply_json.isObject()) { - FLOG_WARN("cannot parse data from github: %1", reply_bytes); - return; - } - - bool current_prerelease = current_reply_json["prerelease"].toBool(); - bool current_draft = current_reply_json["draft"].toBool(); - version_meta_data_.latest_prerelease_version_from_remote = current_prerelease; - version_meta_data_.latest_draft_from_remote = current_draft; -} - -void VersionCheckTask::slot_parse_current_tag_info(QNetworkReply* reply) { - if (reply == nullptr || reply->error() != QNetworkReply::NoError) { - version_meta_data_.current_version_publish_in_remote = false; - return; - } - - version_meta_data_.current_version_publish_in_remote = true; - auto reply_bytes = reply->readAll(); - auto current_reply_json = QJsonDocument::fromJson(reply_bytes); - - if (!current_reply_json.isObject()) { - FLOG_WARN("cannot parse data from github: %1", reply_bytes); - return; - } - - auto object = current_reply_json["object"].toObject(); - if (object["type"].toString() != "commit") { - FLOG_WARN("remote tag: %1 is not a ref: %2", - version_meta_data_.current_version, object["type"].toString()); - return; - } - - auto sha = object["sha"].toString(); - version_meta_data_.remote_commit_hash_by_tag = sha.trimmed(); - FLOG_DEBUG("got remote commit hash: %1", - version_meta_data_.remote_commit_hash_by_tag); -} - -void VersionCheckTask::slot_fill_grt_with_version_info( - const SoftwareVersion& version) { - GFModuleLogDebug("filling software information info in rt..."); - - GFModuleUpsertRTValue(GFGetModuleID(), - GFModuleStrDup("version.current_version"), - GFModuleStrDup(version.current_version.toUtf8())); - GFModuleUpsertRTValue(GFGetModuleID(), - GFModuleStrDup("version.latest_version"), - GFModuleStrDup(version.latest_version.toUtf8())); - GFModuleUpsertRTValue( - GFGetModuleID(), GFModuleStrDup("version.remote_commit_hash_by_tag"), - GFModuleStrDup(version.remote_commit_hash_by_tag.toUtf8())); - GFModuleUpsertRTValue(GFGetModuleID(), - GFModuleStrDup("version.local_commit_hash"), - GFModuleStrDup(version.local_commit_hash.toUtf8())); - - GFModuleUpsertRTValueBool( - GFGetModuleID(), GFModuleStrDup("version.current_version_is_drafted"), - version.current_version_is_drafted ? 1 : 0); - GFModuleUpsertRTValueBool( - GFGetModuleID(), - GFModuleStrDup("version.current_version_is_a_prerelease"), - version.current_version_is_a_prerelease ? 1 : 0); - GFModuleUpsertRTValueBool( - GFGetModuleID(), - GFModuleStrDup("version.current_version_publish_in_remote"), - version.current_version_publish_in_remote ? 1 : 0); - GFModuleUpsertRTValueBool( - GFGetModuleID(), - GFModuleStrDup("version.latest_prerelease_version_from_remote"), - version.latest_prerelease_version_from_remote ? 1 : 0); - GFModuleUpsertRTValueBool(GFGetModuleID(), - GFModuleStrDup("version.need_upgrade"), - version.NeedUpgrade() ? 1 : 0); - GFModuleUpsertRTValueBool(GFGetModuleID(), - GFModuleStrDup("version.current_version_released"), - version.CurrentVersionReleased() ? 1 : 0); - GFModuleUpsertRTValueBool( - GFGetModuleID(), GFModuleStrDup("version.current_a_withdrawn_version"), - version.VersionWithdrawn() ? 1 : 0); - GFModuleUpsertRTValueBool(GFGetModuleID(), - GFModuleStrDup("version.git_commit_hash_mismatch"), - version.GitCommitHashMismatch() ? 1 : 0); - - GFModuleUpsertRTValue(GFGetModuleID(), GFModuleStrDup("version.release_note"), - GFModuleStrDup(version.release_note.toUtf8())); - GFModuleUpsertRTValueBool(GFGetModuleID(), - GFModuleStrDup("version.loading_done"), - version.IsInfoValid() ? 1 : 0); - - GFModuleLogDebug("software information filled in rt"); -} diff --git a/src/m_ver_check/VersionCheckTask.h b/src/m_ver_check/VersionCheckTask.h deleted file mode 100644 index 764c46e..0000000 --- a/src/m_ver_check/VersionCheckTask.h +++ /dev/null @@ -1,106 +0,0 @@ -/** - * Copyright (C) 2021-2024 Saturneric - * - * This file is part of GpgFrontend. - * - * GpgFrontend is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GpgFrontend is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GpgFrontend. If not, see . - * - * The initial version of the source code is inherited from - * the gpg4usb project, which is under GPL-3.0-or-later. - * - * All the source code of GpgFrontend was modified and released by - * Saturneric starting on May 12, 2021. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - */ - -#pragma once - -#include - -#include "SoftwareVersion.h" - -class QNetworkReply; -class QNetworkAccessManager; - -/** - * @brief - * - */ -class VersionCheckTask : public QObject { - Q_OBJECT - public: - /** - * @brief Construct a new Version Check Thread object - * - */ - VersionCheckTask(); - - /** - * @brief - * - * @return int - */ - auto Run() -> int; - - signals: - - /** - * @brief - * - * @param version - */ - void SignalUpgradeVersion(SoftwareVersion version); - - private slots: - - /** - * @brief - * - */ - void slot_parse_reply(QNetworkReply* reply); - - /** - * @brief - * - * @param reply - */ - void slot_parse_latest_version_info(QNetworkReply* reply); - - /** - * @brief - * - * @param reply - */ - void slot_parse_current_version_info(QNetworkReply* reply); - - /** - * @brief - * - * @param reply - */ - void slot_parse_current_tag_info(QNetworkReply* reply); - /** - * @brief - * - */ - void slot_fill_grt_with_version_info(const SoftwareVersion&); - - private: - QList replies_; ///< - QNetworkAccessManager* network_manager_; ///< - QString current_version_; ///< - SoftwareVersion version_meta_data_; -}; diff --git a/src/m_ver_check/VersionCheckingModule.cpp b/src/m_ver_check/VersionCheckingModule.cpp index ea70acc..2a37824 100644 --- a/src/m_ver_check/VersionCheckingModule.cpp +++ b/src/m_ver_check/VersionCheckingModule.cpp @@ -37,14 +37,15 @@ #include #include +#include "BKTUSVersionCheckTask.h" #include "GFModuleCommonUtils.hpp" #include "GFModuleDefine.h" +#include "GitHubVersionCheckTask.h" #include "SoftwareVersion.h" #include "UpdateTab.h" -#include "VersionCheckTask.h" GF_MODULE_API_DEFINE("com.bktus.gpgfrontend.module.version_checking", - "VersionChecking", "1.2.1", + "VersionChecking", "1.3.1", "Try checking GpgFrontend version.", "Saturneric"); DEFINE_TRANSLATIONS_STRUCTURE(ModuleVersionChecking); @@ -74,13 +75,23 @@ EXECUTE_MODULE() { FLOG_INFO("version checking module executing, event id: %1", event["event_id"]); - auto* task = new VersionCheckTask(); - QObject::connect(task, &VersionCheckTask::SignalUpgradeVersion, - QThread::currentThread(), - [event](const SoftwareVersion&) { CB_SUCC(event); }); - QObject::connect(task, &VersionCheckTask::SignalUpgradeVersion, task, - &QObject::deleteLater); - task->Run(); + if (event["source"] == "bktus") { + auto* task = new BKTUSVersionCheckTask(); + QObject::connect(task, &BKTUSVersionCheckTask::SignalUpgradeVersion, + QThread::currentThread(), + [event](const SoftwareVersion&) { CB_SUCC(event); }); + QObject::connect(task, &BKTUSVersionCheckTask::SignalUpgradeVersion, task, + &QObject::deleteLater); + task->Run(); + } else { + auto* task = new GitHubVersionCheckTask(); + QObject::connect(task, &GitHubVersionCheckTask::SignalUpgradeVersion, + QThread::currentThread(), + [event](const SoftwareVersion&) { CB_SUCC(event); }); + QObject::connect(task, &GitHubVersionCheckTask::SignalUpgradeVersion, task, + &QObject::deleteLater); + task->Run(); + } return 0; } -- cgit v1.2.3