Downloader has been generalized, now network_utils is update_utils

This commit is contained in:
Marco Dalla Tiezza
2024-06-13 01:05:53 +02:00
parent 79891899ce
commit 52c4fbcce9
5 changed files with 206 additions and 32 deletions

View File

@@ -7302,7 +7302,7 @@ qt_resource_struct = b"\
\x00\x00\x03X\x00\x02\x00\x00\x00\x04\x00\x00\x00+\ \x00\x00\x03X\x00\x02\x00\x00\x00\x04\x00\x00\x00+\
\x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x04\xc4\x00\x01\x00\x00\x00\x01\x00\x01v\x14\ \x00\x00\x04\xc4\x00\x01\x00\x00\x00\x01\x00\x01v\x14\
\x00\x00\x01\x90\x0eD\xa3A\ \x00\x00\x01\x90\x0eV\xebx\
\x00\x00\x05d\x00\x01\x00\x00\x00\x01\x00\x01\x8f*\ \x00\x00\x05d\x00\x01\x00\x00\x00\x01\x00\x01\x8f*\
\x00\x00\x01\x90\x01\x93J\xb0\ \x00\x00\x01\x90\x01\x93J\xb0\
\x00\x00\x04\xe6\x00\x01\x00\x00\x00\x01\x00\x01\x7f\x0c\ \x00\x00\x04\xe6\x00\x01\x00\x00\x00\x01\x00\x01\x7f\x0c\

View File

@@ -7,7 +7,7 @@ from artemis.utils.constants import Constants, Messages
from artemis.utils.sys_utils import open_directory, make_tar, unpack_tar from artemis.utils.sys_utils import open_directory, make_tar, unpack_tar
from artemis.utils.sql_utils import ArtemisDatabase, ArtemisSignal from artemis.utils.sql_utils import ArtemisDatabase, ArtemisSignal
from artemis.utils.path_utils import DATA_DIR from artemis.utils.path_utils import DATA_DIR
from artemis.utils.network_utils import NetworkManager from artemis.utils.update_utils import UpdateManager
from artemis.utils.generic_utils import generate_filter_query from artemis.utils.generic_utils import generate_filter_query
from artemis.utils.path_utils import normalize_dialog_path from artemis.utils.path_utils import normalize_dialog_path
from artemis.utils.config_utils import CONFIGURE_QT from artemis.utils.config_utils import CONFIGURE_QT
@@ -62,13 +62,12 @@ class UIArtemis(QObject):
# Creating istances for other windows # Creating istances for other windows
self.preferences = UIPreferences(self) self.preferences = UIPreferences(self)
self.dbmanager = UIdbmanager(self) self.dbmanager = UIdbmanager(self)
self.downloader = UIDownloader(self)
self.spaceweather = UIspaceweather(self) self.spaceweather = UIspaceweather(self)
self.docmanager = UIdocumentsmanager(self) self.docmanager = UIdocumentsmanager(self)
self.sigeditor = UIsignaleditor(self) self.sigeditor = UIsignaleditor(self)
self.cateditor = UIcategoryeditor(self) self.cateditor = UIcategoryeditor(self)
self.network_manager = NetworkManager(self) self.update_manager = UpdateManager(self)
self.autoload_db() self.autoload_db()
@@ -217,15 +216,19 @@ class UIArtemis(QObject):
def check_update_db(self): def check_update_db(self):
""" User manual check for updates db updates """ User manual check for updates db updates
""" """
self.network_manager.show_popup = True self.update_manager.check_updates(True)
self.network_manager.check_updates()
def start_download_db(self): def start_download_db(self):
""" Show the downloader and start the download of the sigid db """ Show the downloader and start the download of the sigid db
""" """
self.downloader.show_ui.emit() self.downloader = UIDownloader(self)
self.downloader.on_start() self.downloader.finished.connect(self.update_manager.post_download_db)
self.downloader.on_start(
self.update_manager.remote_db_url,
self.update_manager.remote_db_size,
DATA_DIR
)
def dialog_download_db(self, message_type, title, message): def dialog_download_db(self, message_type, title, message):

View File

@@ -2,14 +2,12 @@ from PySide6.QtQml import QQmlApplicationEngine
from PySide6.QtCore import QObject, Slot, Signal, QUrl, QSaveFile, QDir, QIODevice from PySide6.QtCore import QObject, Slot, Signal, QUrl, QSaveFile, QDir, QIODevice
from PySide6.QtNetwork import QNetworkReply, QNetworkRequest, QNetworkAccessManager from PySide6.QtNetwork import QNetworkReply, QNetworkRequest, QNetworkAccessManager
from artemis.utils.config_utils import *
from artemis.utils.sys_utils import delete_file, delete_dir, match_hash, unpack_tar
from artemis.utils.constants import Messages from artemis.utils.constants import Messages
from artemis.utils.path_utils import DATA_DIR
class UIDownloader(QObject): class UIDownloader(QObject):
# Python > QML Signals # Python > QML Signals
finished = Signal()
show_ui = Signal() show_ui = Signal()
close_ui = Signal() close_ui = Signal()
update_progress_bar = Signal(int, int) update_progress_bar = Signal(int, int)
@@ -25,6 +23,9 @@ class UIDownloader(QObject):
self._engine.load('qrc:/ui/Downloader.qml') self._engine.load('qrc:/ui/Downloader.qml')
self._window = self._engine.rootObjects()[0] self._window = self._engine.rootObjects()[0]
self.file_url = None
self.file_size = None
self._connect() self._connect()
@@ -39,20 +40,22 @@ class UIDownloader(QObject):
self.update_status.connect(self._window.updateStatus) self.update_status.connect(self._window.updateStatus)
@Slot() def on_start(self, url, filesize, save_path):
def on_start(self):
""" Start the download of the DB taking the needed url and size from """ Start the download of the DB taking the needed url and size from
the attributes of the UpdatesController class the attributes of the UpdatesController class
""" """
url_file = QUrl(self._parent.network_manager.remote_db_url) self.show_ui.emit()
dest_path = QDir(DATA_DIR)
self.dest_file = dest_path.filePath(url_file.fileName()) self.file_url = QUrl(url)
self.file_size = filesize
dest_path = QDir(save_path)
self.dest_file = dest_path.filePath(self.file_url.fileName())
self.file = QSaveFile(self.dest_file) self.file = QSaveFile(self.dest_file)
if self.file.open(QIODevice.WriteOnly): if self.file.open(QIODevice.WriteOnly):
# Start a GET HTTP request # Start a GET HTTP request
self.manager = QNetworkAccessManager(self) self.manager = QNetworkAccessManager(self)
self.reply = self.manager.get(QNetworkRequest(url_file)) self.reply = self.manager.get(QNetworkRequest(self.file_url))
self.reply.downloadProgress.connect(self.on_progress) self.reply.downloadProgress.connect(self.on_progress)
self.reply.finished.connect(self.on_finished) self.reply.finished.connect(self.on_finished)
self.reply.readyRead.connect(self.on_ready_read) self.reply.readyRead.connect(self.on_ready_read)
@@ -74,8 +77,6 @@ class UIDownloader(QObject):
if self.file: if self.file:
self.file.cancelWriting() self.file.cancelWriting()
self.close_ui.emit()
@Slot() @Slot()
def on_ready_read(self): def on_ready_read(self):
@@ -95,25 +96,19 @@ class UIDownloader(QObject):
if self.file: if self.file:
self.file.commit() self.file.commit()
if self.reply.error() == QNetworkReply.NoError:
self.finished.emit()
self.update_status.emit("Checking DB integrity (SHA-256)") self.close_ui.emit()
if match_hash(self.dest_file, self._parent.network_manager.remote_db_hash):
self.update_status.emit("Unpacking archive...")
delete_dir(DATA_DIR / 'SigID')
unpack_tar(self.dest_file, DATA_DIR / 'SigID')
delete_file(self.dest_file)
self._parent.load_db('SigID')
self.close_ui.emit()
@Slot(int, int) @Slot(int, int)
def on_progress(self, bytesReceived: int): def on_progress(self, bytesReceived: int):
""" Update progress bar and label """ Update progress bar and label
""" """
total_bytes = self._parent.network_manager.remote_db_size self.update_status.emit("{:.1f} Mb / {:.1f} Mb".format(bytesReceived/10**6, self.file_size/10**6))
self.update_status.emit("{:.1f} Mb / {:.1f} Mb".format(bytesReceived/10**6, total_bytes/10**6)) self.update_progress_bar.emit(bytesReceived, self.file_size)
self.update_progress_bar.emit(bytesReceived, total_bytes)
@Slot(QNetworkReply.NetworkError) @Slot(QNetworkReply.NetworkError)

View File

@@ -39,6 +39,7 @@ class Messages:
UP_TO_DATE = "You're up to date!" UP_TO_DATE = "You're up to date!"
DB_NEW_VER = "New SigID DB version available!" DB_NEW_VER = "New SigID DB version available!"
ART_NEW_VER = "New Artemis version available!" ART_NEW_VER = "New Artemis version available!"
DB_CORRUPTED = "Database Corruption Detected"
# Messages # Messages
DB_CREATION_SUCCESS_MSG = "The new database has been created succesfully." DB_CREATION_SUCCESS_MSG = "The new database has been created succesfully."
@@ -51,7 +52,8 @@ class Messages:
UP_TO_DATE_MSG = "The latest version of Artemis and SigID wiki is installed on your computer." UP_TO_DATE_MSG = "The latest version of Artemis and SigID wiki is installed on your computer."
DB_NEW_VER_MSG = "A new version of the database ({}) is available for download. Download now?" DB_NEW_VER_MSG = "A new version of the database ({}) is available for download. Download now?"
ART_NEW_VER_MSG = "A new version of Artemis ({}) is available for download. Check GitHub page now?" ART_NEW_VER_MSG = "A new version of Artemis ({}) is available for download. Check GitHub page now?"
DOWNLOAD_CORRUPTED_MSG = "Downloaded data corrupted or invalid. Please retry." DB_CORRUPTED_MSG = "Downloaded data corrupted or invalid. Please retry."
DB_DOWNLOAD_SUCCESS_MSG = "The database has been successfully downloaded and is now being loaded."
class Query(): class Query():

View File

@@ -0,0 +1,174 @@
import os
import requests
from packaging.version import Version
from artemis.utils.constants import Constants, Messages
from artemis.utils.sql_utils import ArtemisDatabase
from artemis.utils.sys_utils import is_windows, is_linux, is_macos, delete_file, delete_dir, match_hash, unpack_tar
from artemis.utils.path_utils import DATA_DIR
class UpdateManager:
""" Class used to manage DB and software updates
"""
def __init__(self, parent):
self._parent = parent
self.sigid_db_path = DATA_DIR / 'SigID' / Constants.SQL_NAME
self.db_update = None
self.art_update = None
self.remote_db_url = None
self.remote_db_hash = None
self.remote_db_version = None
self.remote_db_size = None
self.remote_db_file_name = None
self.remote_art_version = None
self.check_updates()
def check_updates(self, show_popup=False):
""" Checks if a software or DB update is available.
Prioritize Artemis update over DB one.
Args:
show_popup (bool, optional):
Suppress the "already up-to-date" message on startup.
Defaults to False.
"""
latest_json = self._fetch_remote_json(Constants.LATEST_VERSION_URL, show_popup)
if latest_json:
local_db = self._load_local_db()
remote_db = latest_json['sigID_DB']
self.remote_db_version = remote_db['version']
self.remote_db_url = remote_db['url']
self.remote_db_hash = remote_db['sha256_hash']
self.remote_db_size = remote_db['total_bytes']
self.remote_db_file_name = self.remote_db_url.split('/')[-1]
if is_windows():
self.remote_art_version = latest_json['windows']['version']
elif is_linux():
self.remote_art_version = latest_json['linux']['version']
elif is_macos():
self.remote_art_version = latest_json['mac']['version']
if Version(self.remote_art_version) > Version(Constants.APPLICATION_VERSION):
self.art_update = True
else:
self.art_update = False
if self.art_update:
self._show_popup_art_update()
else:
if local_db:
if self.remote_db_version > local_db.version:
self._show_popup_db_update()
elif show_popup:
self._show_popup_up_to_date()
else:
self._show_popup_initial_db_download()
def _fetch_remote_json(self, url, show_popup=False):
""" Fetches the remote json from a url
"""
try:
response = requests.get(url)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
if show_popup:
self._parent.dialog_popup(
Messages.DIALOG_TYPE_ERROR,
Messages.NO_CONNECTION,
Messages.NO_CONNECTION_MSG.format(e)
)
return None
def _load_local_db(self):
""" Loads the local database if exists
"""
if os.path.exists(self.sigid_db_path):
local_db = ArtemisDatabase('SigID')
local_db.load()
return local_db
return None
def post_download_db(self):
latest_db_tar_path = DATA_DIR / self.remote_db_file_name
if match_hash(latest_db_tar_path, self.remote_db_hash):
delete_dir(DATA_DIR / 'SigID')
unpack_tar(latest_db_tar_path, DATA_DIR / 'SigID')
self._parent.load_db('SigID')
self._show_popup_db_download_complete()
else:
self._show_popup_db_hash_failed()
delete_file(latest_db_tar_path)
def _show_popup_db_update(self):
""" Prompts the user to download the updated version of the database.
"""
self._parent.dialog_download_db(
Messages.DIALOG_TYPE_WARN,
Messages.DB_NEW_VER,
Messages.DB_NEW_VER_MSG.format(self.remote_db_version)
)
def _show_popup_art_update(self):
""" Prompts the user to download the updated version of the database.
"""
self._parent.dialog_download_artemis(
Messages.DIALOG_TYPE_WARN,
Messages.ART_NEW_VER,
Messages.ART_NEW_VER_MSG.format(self.remote_art_version)
)
def _show_popup_up_to_date(self):
""" Notifies the user that the database is up to date.
"""
self._parent.dialog_popup(
Messages.DIALOG_TYPE_INFO,
Messages.UP_TO_DATE,
Messages.UP_TO_DATE_MSG
)
def _show_popup_initial_db_download(self):
""" Prompts the user to download the database for the first time.
"""
self._parent.dialog_download_db(
Messages.DIALOG_TYPE_QUEST,
Messages.NO_DB_DETECTED,
Messages.NO_DB_DETECTED_MSG
)
def _show_popup_db_download_complete(self):
""" DB has been succesfully downloaded
"""
self._parent.dialog_popup(
Messages.DIALOG_TYPE_INFO,
Messages.GENERIC_SUCCESS,
Messages.DB_DOWNLOAD_SUCCESS_MSG
)
def _show_popup_db_hash_failed(self):
""" Notify the user after detection of a corrupted database
"""
self._parent.dialog_popup(
Messages.DIALOG_TYPE_ERROR,
Messages.DB_CORRUPTED,
Messages.DB_CORRUPTED_MSG
)