Downloader has been generalized, now network_utils is update_utils
This commit is contained in:
@@ -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\
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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):
|
||||||
@@ -96,14 +97,9 @@ class UIDownloader(QObject):
|
|||||||
if self.file:
|
if self.file:
|
||||||
self.file.commit()
|
self.file.commit()
|
||||||
|
|
||||||
self.update_status.emit("Checking DB integrity (SHA-256)")
|
if self.reply.error() == QNetworkReply.NoError:
|
||||||
|
self.finished.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()
|
self.close_ui.emit()
|
||||||
|
|
||||||
|
|
||||||
@@ -111,9 +107,8 @@ class UIDownloader(QObject):
|
|||||||
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)
|
||||||
|
|||||||
@@ -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():
|
||||||
|
|||||||
174
artemis/utils/update_utils.py
Normal file
174
artemis/utils/update_utils.py
Normal 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
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user