Merge pull request #51 from AresValley/revised-networking
Revised network manager, update manager and downloader
This commit is contained in:
7336
artemis/resources.py
7336
artemis/resources.py
File diff suppressed because it is too large
Load Diff
@@ -6,10 +6,10 @@ from PySide6.QtCore import QObject, Slot, Signal
|
||||
from artemis.utils.constants import Constants, Messages
|
||||
from artemis.utils.sys_utils import open_directory, make_tar, unpack_tar
|
||||
from artemis.utils.sql_utils import ArtemisDatabase, ArtemisSignal
|
||||
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.path_utils import normalize_dialog_path
|
||||
from artemis.utils.path_utils import DATA_DIR
|
||||
from artemis.utils.config_utils import CONFIGURE_QT
|
||||
|
||||
from artemis.ui.preferences import UIPreferences
|
||||
@@ -25,6 +25,7 @@ import artemis.resources
|
||||
|
||||
class UIArtemis(QObject):
|
||||
# Python > QML Signals
|
||||
close_ui = Signal()
|
||||
populate_sig_list = Signal(list)
|
||||
populate_sig_details = Signal(list)
|
||||
populate_filter_modulation = Signal(list)
|
||||
@@ -37,7 +38,7 @@ class UIArtemis(QObject):
|
||||
|
||||
show_dialog_popup = Signal(str, str, str)
|
||||
show_dialog_download_db = Signal(str, str, str)
|
||||
show_dialog_download_art = Signal(str, str, str)
|
||||
show_dialog_update_artemis = Signal(str, str, str, bool)
|
||||
update_info_bar = Signal(str, str)
|
||||
|
||||
|
||||
@@ -62,13 +63,13 @@ class UIArtemis(QObject):
|
||||
# Creating istances for other windows
|
||||
self.preferences = UIPreferences(self)
|
||||
self.dbmanager = UIdbmanager(self)
|
||||
self.downloader = UIDownloader(self)
|
||||
self.spaceweather = UIspaceweather(self)
|
||||
self.docmanager = UIdocumentsmanager(self)
|
||||
self.sigeditor = UIsignaleditor(self)
|
||||
self.cateditor = UIcategoryeditor(self)
|
||||
self.downloader = UIDownloader(self)
|
||||
|
||||
self.network_manager = NetworkManager(self)
|
||||
self.update_manager = UpdateManager(self)
|
||||
|
||||
self.autoload_db()
|
||||
|
||||
@@ -79,8 +80,9 @@ class UIArtemis(QObject):
|
||||
self._window.loadSignal.connect(self.load_sig)
|
||||
self._window.showPref.connect(self.show_pref_ui)
|
||||
self._window.openSigEditor.connect(self.open_sig_editor)
|
||||
self._window.startDownloader.connect(self.start_download_db)
|
||||
self._window.checkDbUpdates.connect(self.check_update_db)
|
||||
self._window.checkForUpdate.connect(self.check_for_update)
|
||||
self._window.updateDb.connect(self.update_db)
|
||||
self._window.updateArtemis.connect(self.update_artemis)
|
||||
self._window.showSpaceWeather.connect(self.show_space_weather_ui)
|
||||
self._window.openDbDirectory.connect(self.open_db_directory)
|
||||
self._window.showCatManager.connect(self.open_cat_manager)
|
||||
@@ -98,12 +100,13 @@ class UIArtemis(QObject):
|
||||
self._window_signal.addCatTag.connect(self.add_cat_tag)
|
||||
|
||||
# Python > QML connections
|
||||
self.close_ui.connect(self._window.close)
|
||||
self.populate_sig_list.connect(self._window.populateList)
|
||||
self.clear_list.connect(self._window.clearList)
|
||||
self.update_info_bar.connect(self._window.bottomInfoBar)
|
||||
self.show_dialog_popup.connect(self._window.openGeneralDialog)
|
||||
self.show_dialog_download_db.connect(self._window.openDialogDownloadDb)
|
||||
self.show_dialog_download_art.connect(self._window.openDialogDownloadArtemis)
|
||||
self.show_dialog_update_artemis.connect(self._window.openDialogUpdateArtemis)
|
||||
self.lock_menu.connect(self._window.lockMenu)
|
||||
|
||||
self.populate_sig_details.connect(self._window_signal.populateSignalParam)
|
||||
@@ -214,18 +217,10 @@ class UIArtemis(QObject):
|
||||
self.docmanager.load_documentsmanager_ui()
|
||||
|
||||
|
||||
def check_update_db(self):
|
||||
""" User manual check for updates db updates
|
||||
def check_for_update(self):
|
||||
""" User manual check for updates updates
|
||||
"""
|
||||
self.network_manager.show_popup = True
|
||||
self.network_manager.check_updates()
|
||||
|
||||
|
||||
def start_download_db(self):
|
||||
""" Show the downloader and start the download of the sigid db
|
||||
"""
|
||||
self.downloader.show_ui.emit()
|
||||
self.downloader.on_start()
|
||||
self.update_manager.check_updates(True)
|
||||
|
||||
|
||||
def dialog_download_db(self, message_type, title, message):
|
||||
@@ -234,10 +229,24 @@ class UIArtemis(QObject):
|
||||
self.show_dialog_download_db.emit(message_type, title, message)
|
||||
|
||||
|
||||
def dialog_download_artemis(self, message_type, title, message):
|
||||
""" Dialog popup for artemis download confirmation
|
||||
def dialog_update_artemis(self, message_type, title, message, auto=False):
|
||||
""" Dialog popup for Artemis download confirmation
|
||||
"""
|
||||
self.show_dialog_download_art.emit(message_type, title, message)
|
||||
self.show_dialog_update_artemis.emit(message_type, title, message, auto)
|
||||
|
||||
|
||||
@Slot()
|
||||
def update_db(self):
|
||||
""" Start the download of the sigID DB
|
||||
"""
|
||||
self.update_manager.download_db()
|
||||
|
||||
|
||||
@Slot()
|
||||
def update_artemis(self):
|
||||
""" Start the download of Artemis
|
||||
"""
|
||||
self.update_manager.download_artemis()
|
||||
|
||||
|
||||
def open_db_directory(self):
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import requests
|
||||
|
||||
from PySide6.QtQml import QQmlApplicationEngine
|
||||
from PySide6.QtCore import QObject, Slot, Signal, QUrl, QSaveFile, QDir, QIODevice
|
||||
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.path_utils import DATA_DIR
|
||||
|
||||
|
||||
class UIDownloader(QObject):
|
||||
@@ -13,7 +12,9 @@ class UIDownloader(QObject):
|
||||
show_ui = Signal()
|
||||
close_ui = Signal()
|
||||
update_progress_bar = Signal(int, int)
|
||||
set_indeterminate_bar = Signal()
|
||||
update_status = Signal(str)
|
||||
finished = Signal()
|
||||
|
||||
|
||||
def __init__(self, parent):
|
||||
@@ -25,6 +26,13 @@ class UIDownloader(QObject):
|
||||
self._engine.load('qrc:/ui/Downloader.qml')
|
||||
self._window = self._engine.rootObjects()[0]
|
||||
|
||||
self.file_url = None
|
||||
self.file_size = None
|
||||
self.dest_file = None
|
||||
self.file = None
|
||||
self.manager = None
|
||||
self.reply = None
|
||||
|
||||
self._connect()
|
||||
|
||||
|
||||
@@ -36,50 +44,54 @@ class UIDownloader(QObject):
|
||||
self.show_ui.connect(self._window.show)
|
||||
self.close_ui.connect(self._window.close)
|
||||
self.update_progress_bar.connect(self._window.updateProgressBar)
|
||||
self.set_indeterminate_bar.connect(self._window.setIndeterminateBar)
|
||||
self.update_status.connect(self._window.updateStatus)
|
||||
|
||||
|
||||
@Slot()
|
||||
def on_start(self):
|
||||
""" Start the download of the DB taking the needed url and size from
|
||||
the attributes of the UpdatesController class
|
||||
def on_start(self, url, save_path):
|
||||
""" Start the download process using the specified URL
|
||||
|
||||
Args:
|
||||
url (str): url from where download the file
|
||||
save_path (str): path where to save the downloaded file
|
||||
"""
|
||||
url_file = QUrl(self._parent.network_manager.remote_db_url)
|
||||
dest_path = QDir(DATA_DIR)
|
||||
self.dest_file = dest_path.filePath(url_file.fileName())
|
||||
self._clear_ui()
|
||||
self.show_ui.emit()
|
||||
|
||||
self.file_url = QUrl(url)
|
||||
self.file_size = self._get_filesize(url)
|
||||
dest_path = QDir(save_path)
|
||||
self.dest_file = dest_path.filePath(self.file_url.fileName())
|
||||
self.file = QSaveFile(self.dest_file)
|
||||
|
||||
if self.file.open(QIODevice.WriteOnly):
|
||||
# Start a GET HTTP request
|
||||
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.finished.connect(self.on_finished)
|
||||
self.reply.readyRead.connect(self.on_ready_read)
|
||||
self.reply.errorOccurred.connect(self.on_error)
|
||||
else:
|
||||
self.close_ui.emit()
|
||||
self.show_popup_error(
|
||||
self.file.errorString()
|
||||
)
|
||||
self.show_popup_error(self.file.errorString())
|
||||
|
||||
|
||||
@Slot()
|
||||
def on_abort(self):
|
||||
""" Stop the download when user press abort button """
|
||||
""" Stop the download when user presses the abort button
|
||||
"""
|
||||
if self.reply:
|
||||
self.reply.abort()
|
||||
self.update_progress_bar.emit(0, 0)
|
||||
|
||||
if self.file:
|
||||
self.file.cancelWriting()
|
||||
|
||||
self.close_ui.emit()
|
||||
|
||||
|
||||
@Slot()
|
||||
def on_ready_read(self):
|
||||
""" Get available bytes and store them into the file """
|
||||
""" Write available bytes to the file
|
||||
"""
|
||||
if self.reply:
|
||||
if self.reply.error() == QNetworkReply.NoError:
|
||||
self.file.write(self.reply.readAll())
|
||||
@@ -87,8 +99,9 @@ class UIDownloader(QObject):
|
||||
|
||||
@Slot()
|
||||
def on_finished(self):
|
||||
""" Delete reply, close the file, check the hash for integrity,
|
||||
extract the database and delete the downloaded zip
|
||||
""" Finalize the download process and, if no errors
|
||||
occurs, emits the finished signal usefull for
|
||||
a callback
|
||||
"""
|
||||
if self.reply:
|
||||
self.reply.deleteLater()
|
||||
@@ -96,24 +109,21 @@ class UIDownloader(QObject):
|
||||
if self.file:
|
||||
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()
|
||||
|
||||
|
||||
@Slot(int, int)
|
||||
def on_progress(self, bytesReceived: int):
|
||||
""" Update progress bar and label
|
||||
""" Update progress bar and status label
|
||||
"""
|
||||
total_bytes = self._parent.network_manager.remote_db_size
|
||||
self.update_status.emit("{:.1f} Mb / {:.1f} Mb".format(bytesReceived/10**6, total_bytes/10**6))
|
||||
self.update_progress_bar.emit(bytesReceived, total_bytes)
|
||||
if self.file_size is not None:
|
||||
self.update_status.emit("{:.1f} Mb / {:.1f} Mb".format(bytesReceived/10**6, self.file_size/10**6))
|
||||
self.update_progress_bar.emit(bytesReceived, self.file_size)
|
||||
else:
|
||||
self.update_status.emit("{:.1f} Mb".format(bytesReceived/10**6))
|
||||
|
||||
|
||||
@Slot(QNetworkReply.NetworkError)
|
||||
@@ -127,6 +137,28 @@ class UIDownloader(QObject):
|
||||
)
|
||||
|
||||
|
||||
def _get_filesize(self, url):
|
||||
""" Get the file size by sending a HEAD request to the URL.
|
||||
If the Content-Length in HTTP headers is missing, returns None
|
||||
and set the progress_bar as 'indeterminate' like a 'busy indicator'
|
||||
|
||||
Args:
|
||||
url (str): URL to check the file size
|
||||
"""
|
||||
try:
|
||||
response = requests.get(url, stream=True)
|
||||
size = int(response.headers.get('content-length'))
|
||||
return size
|
||||
except:
|
||||
self.set_indeterminate_bar.emit()
|
||||
return None
|
||||
|
||||
|
||||
def _clear_ui(self):
|
||||
self.update_progress_bar.emit(0, 0)
|
||||
self.update_status.emit('')
|
||||
|
||||
|
||||
def show_popup_error(self, error_msg):
|
||||
self._parent.dialog_popup(
|
||||
Messages.DIALOG_TYPE_ERROR,
|
||||
|
||||
@@ -53,10 +53,10 @@ class UIspaceweather(QObject):
|
||||
|
||||
|
||||
def download_poseidon_report(self):
|
||||
network_manager = self._parent.network_manager
|
||||
network_manager.show_popup = True
|
||||
poseidon_data = network_manager.fetch_remote_json(
|
||||
Constants.POSEIDON_REPORT_URL
|
||||
update_manager = self._parent.update_manager
|
||||
poseidon_data = update_manager.fetch_remote_json(
|
||||
Constants.POSEIDON_REPORT_URL,
|
||||
True
|
||||
)
|
||||
if poseidon_data:
|
||||
self.load_poseidon_report.emit(poseidon_data)
|
||||
|
||||
@@ -39,6 +39,7 @@ class Messages:
|
||||
UP_TO_DATE = "You're up to date!"
|
||||
DB_NEW_VER = "New SigID DB version available!"
|
||||
ART_NEW_VER = "New Artemis version available!"
|
||||
DB_CORRUPTED = "Database Corruption Detected"
|
||||
|
||||
# Messages
|
||||
DB_CREATION_SUCCESS_MSG = "The new database has been created succesfully."
|
||||
@@ -50,8 +51,10 @@ class Messages:
|
||||
NO_CONNECTION_MSG = "Unable to check for updates. It appears that there is a problem with your internet connection. Please check your network settings and try again later. {}"
|
||||
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?"
|
||||
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."
|
||||
ART_NEW_VER_MANUAL_MSG = "A new version of Artemis ({}) is available for download. Check GitHub page now?"
|
||||
ART_NEW_VER_AUTO_MSG = "A new version of Artemis ({}) is available for download. Update Artemis now?"
|
||||
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():
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
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
|
||||
from artemis.utils.path_utils import DATA_DIR
|
||||
|
||||
|
||||
class NetworkManager:
|
||||
""" Class that checks for DB or software updates
|
||||
"""
|
||||
|
||||
def __init__(self, parent):
|
||||
self._parent = parent
|
||||
self.sigid_db_path = DATA_DIR / 'SigID' / Constants.SQL_NAME
|
||||
|
||||
self.show_popup = False
|
||||
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_art_version = None
|
||||
|
||||
self.check_updates()
|
||||
|
||||
|
||||
def check_updates(self):
|
||||
""" Checks if a new DB update is available.
|
||||
|
||||
Args:
|
||||
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)
|
||||
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']
|
||||
|
||||
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 self.show_popup:
|
||||
self.show_popup_up_to_date()
|
||||
else:
|
||||
self.show_popup_initial_db_download()
|
||||
|
||||
|
||||
def fetch_remote_json(self, url):
|
||||
""" 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 self.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 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
|
||||
)
|
||||
@@ -36,6 +36,15 @@ def _data_dir():
|
||||
return data_dir_path
|
||||
|
||||
|
||||
def _tmp_dir():
|
||||
if is_windows():
|
||||
tmp_dir_path = Path.home() / 'AppData' / 'Local' / 'Temp'
|
||||
else:
|
||||
tmp_dir_path = Path('/tmp')
|
||||
|
||||
return tmp_dir_path
|
||||
|
||||
|
||||
def _preference_dir():
|
||||
preference_dir_path = APP_DIR / 'config'
|
||||
if not preference_dir_path.exists():
|
||||
@@ -46,4 +55,5 @@ def _preference_dir():
|
||||
BASE_DIR = Path(os.path.dirname(__file__)) / '../..'
|
||||
APP_DIR = _app_dir()
|
||||
DATA_DIR = _data_dir()
|
||||
TMP_DIR = _tmp_dir()
|
||||
PREFERENCES_DIR = _preference_dir()
|
||||
|
||||
234
artemis/utils/update_utils.py
Normal file
234
artemis/utils/update_utils.py
Normal file
@@ -0,0 +1,234 @@
|
||||
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, open_file
|
||||
from artemis.utils.path_utils import DATA_DIR, TMP_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_artemis_version = None
|
||||
self.remote_artemis_url = None
|
||||
self.remote_artemis_file_name = None
|
||||
|
||||
self.check_updates()
|
||||
|
||||
|
||||
def check_updates(self, show_popup=False):
|
||||
""" Checks if a software or DB update is available.
|
||||
Prioritize Artemis updates over the DB one.
|
||||
|
||||
Args:
|
||||
show_popup (bool, optional):
|
||||
If False, suppress the "already up-to-date" message on startup.
|
||||
Defaults to False. True is usefull when the user manual check for
|
||||
updates.
|
||||
"""
|
||||
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_artemis_version = latest_json['windows']['version']
|
||||
self.remote_artemis_url = latest_json['windows']['url']
|
||||
elif is_linux():
|
||||
self.remote_artemis_version = latest_json['linux']['version']
|
||||
self.remote_artemis_url = latest_json['linux']['url']
|
||||
elif is_macos():
|
||||
self.remote_artemis_version = latest_json['mac']['version']
|
||||
self.remote_artemis_url = latest_json['mac']['url']
|
||||
|
||||
self.remote_artemis_file_name = self.remote_artemis_url.split('/')[-1]
|
||||
|
||||
if Version(self.remote_artemis_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
|
||||
|
||||
Args:
|
||||
show_popup (bool, optional): If false, suppress any error message
|
||||
Defaults to False (to avoid error if the program is used offline)
|
||||
"""
|
||||
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 download_db(self):
|
||||
""" Open the downloader and download the sigID database in the
|
||||
TMP_DIR folder. After a succesfull download the callback function
|
||||
from the downloader is post_download_db
|
||||
"""
|
||||
self._parent.downloader.finished.connect(self.post_download_db)
|
||||
self._parent.downloader.on_start(
|
||||
self.remote_db_url,
|
||||
TMP_DIR
|
||||
)
|
||||
|
||||
|
||||
def post_download_db(self):
|
||||
""" After a succesfull DB download, this function check the hash
|
||||
for possible corrupted data, delete old sigID DB and extract
|
||||
the new one
|
||||
"""
|
||||
latest_db_tar_path = TMP_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 download_artemis(self):
|
||||
""" Open the downloader and download Artemis in the
|
||||
TMP_DIR folder. After a succesfull download the callback function
|
||||
from the downloader is post_download_artemis
|
||||
"""
|
||||
self._parent.downloader.finished.connect(self.post_download_artemis)
|
||||
self._parent.downloader.on_start(
|
||||
self.remote_artemis_url,
|
||||
TMP_DIR
|
||||
)
|
||||
|
||||
|
||||
def post_download_artemis(self):
|
||||
""" After a succesfull Artemis download, this open the installer
|
||||
and close the application
|
||||
"""
|
||||
if is_windows():
|
||||
open_file(TMP_DIR / self.remote_artemis_file_name)
|
||||
self._parent.close_ui.emit()
|
||||
|
||||
|
||||
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):
|
||||
""" Alerts the user of a new version of Artemis.
|
||||
Windows - asks to download with automatic update
|
||||
Linux, macOS - redirects to GitHub page
|
||||
"""
|
||||
if is_windows():
|
||||
self._parent.dialog_update_artemis(
|
||||
Messages.DIALOG_TYPE_QUEST,
|
||||
Messages.ART_NEW_VER,
|
||||
Messages.ART_NEW_VER_AUTO_MSG.format(self.remote_artemis_version),
|
||||
True
|
||||
)
|
||||
else:
|
||||
self._parent.dialog_update_artemis(
|
||||
Messages.DIALOG_TYPE_QUEST,
|
||||
Messages.ART_NEW_VER,
|
||||
Messages.ART_NEW_VER_MANUAL_MSG.format(self.remote_artemis_version),
|
||||
False
|
||||
)
|
||||
|
||||
|
||||
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
|
||||
)
|
||||
@@ -31,8 +31,9 @@ Window {
|
||||
signal showCatManager()
|
||||
signal openSigEditor(string type, var sig_param, bool is_new)
|
||||
signal showSpaceWeather()
|
||||
signal checkDbUpdates()
|
||||
signal startDownloader()
|
||||
signal checkForUpdate()
|
||||
signal updateDb()
|
||||
signal updateArtemis()
|
||||
signal openDbDirectory()
|
||||
signal newDb(string name)
|
||||
signal exportDb(string path)
|
||||
@@ -121,11 +122,12 @@ Window {
|
||||
dialogDownloadDb.open()
|
||||
}
|
||||
|
||||
function openDialogDownloadArtemis(messageType, title, message) {
|
||||
dialogDownloadArtemis.messageType = messageType
|
||||
dialogDownloadArtemis.title = title
|
||||
dialogDownloadArtemis.message = message
|
||||
dialogDownloadArtemis.open()
|
||||
function openDialogUpdateArtemis(messageType, title, message, auto) {
|
||||
dialogUpdateArtemis.messageType = messageType
|
||||
dialogUpdateArtemis.title = title
|
||||
dialogUpdateArtemis.message = message
|
||||
dialogUpdateArtemis.autoUpdate = auto
|
||||
dialogUpdateArtemis.open()
|
||||
}
|
||||
|
||||
DialogMessage {
|
||||
@@ -135,18 +137,24 @@ Window {
|
||||
standardButtons: Dialog.Cancel | Dialog.Yes
|
||||
|
||||
onAccepted: {
|
||||
startDownloader()
|
||||
updateDb()
|
||||
}
|
||||
}
|
||||
|
||||
DialogMessage {
|
||||
id: dialogDownloadArtemis
|
||||
id: dialogUpdateArtemis
|
||||
modal: true
|
||||
|
||||
property bool autoUpdate
|
||||
|
||||
standardButtons: Dialog.Cancel | Dialog.Yes
|
||||
|
||||
onAccepted: {
|
||||
Qt.openUrlExternally("https://github.com/AresValley/Artemis")
|
||||
if (autoUpdate) {
|
||||
updateArtemis();
|
||||
} else {
|
||||
Qt.openUrlExternally("https://github.com/AresValley/Artemis");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,7 +328,7 @@ Window {
|
||||
|
||||
MenuItem {
|
||||
text: "Check for Updates"
|
||||
onClicked: {checkDbUpdates()}
|
||||
onClicked: {checkForUpdate()}
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
@@ -24,11 +24,19 @@ Window {
|
||||
|
||||
signal onAbort()
|
||||
|
||||
onClosing: {
|
||||
onAbort()
|
||||
}
|
||||
|
||||
function updateProgressBar(bytesReceived, bytesTotal) {
|
||||
progressBar.value = bytesReceived
|
||||
progressBar.to = bytesTotal
|
||||
}
|
||||
|
||||
function setIndeterminateBar() {
|
||||
progressBar.indeterminate = true
|
||||
}
|
||||
|
||||
function updateStatus(arg) {
|
||||
progressLabel.text = arg
|
||||
}
|
||||
@@ -51,6 +59,7 @@ Window {
|
||||
Layout.rightMargin: 20
|
||||
Layout.leftMargin: 20
|
||||
Layout.fillWidth: true
|
||||
indeterminate: false
|
||||
value: 0
|
||||
to: 0
|
||||
}
|
||||
@@ -61,10 +70,11 @@ Window {
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
|
||||
text: qsTr("Abort")
|
||||
icon.source: "qrc:/images/icons/abort.svg"
|
||||
display: AbstractButton.TextBesideIcon
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
|
||||
flat: true
|
||||
onClicked: { onAbort() }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user