forked from openlp/openlp
Better handle failed downloads
This commit is contained in:
parent
121f0908a1
commit
6d2b1d958e
@ -60,6 +60,35 @@ def init_db(url, auto_flush=True, auto_commit=False, base=None):
|
|||||||
return session, metadata
|
return session, metadata
|
||||||
|
|
||||||
|
|
||||||
|
def get_db_path(plugin_name, db_file_name=None):
|
||||||
|
"""
|
||||||
|
Create a path to a database from the plugin name and database name
|
||||||
|
|
||||||
|
:param plugin_name: Name of plugin
|
||||||
|
:param db_file_name: File name of database
|
||||||
|
:return: The path to the database as type str
|
||||||
|
"""
|
||||||
|
if db_file_name is None:
|
||||||
|
return 'sqlite:///%s/%s.sqlite' % (AppLocation.get_section_data_path(plugin_name), plugin_name)
|
||||||
|
else:
|
||||||
|
return 'sqlite:///%s/%s' % (AppLocation.get_section_data_path(plugin_name), db_file_name)
|
||||||
|
|
||||||
|
|
||||||
|
def handle_db_error(plugin_name, db_file_name):
|
||||||
|
"""
|
||||||
|
Log and report to the user that a database cannot be loaded
|
||||||
|
|
||||||
|
:param plugin_name: Name of plugin
|
||||||
|
:param db_file_name: File name of database
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
db_path = get_db_path(plugin_name, db_file_name)
|
||||||
|
log.exception('Error loading database: %s', db_path)
|
||||||
|
critical_error_message_box(translate('OpenLP.Manager', 'Database Error'),
|
||||||
|
translate('OpenLP.Manager', 'OpenLP cannot load your database.\n\nDatabase: %s')
|
||||||
|
% db_path)
|
||||||
|
|
||||||
|
|
||||||
def init_url(plugin_name, db_file_name=None):
|
def init_url(plugin_name, db_file_name=None):
|
||||||
"""
|
"""
|
||||||
Return the database URL.
|
Return the database URL.
|
||||||
@ -69,13 +98,9 @@ def init_url(plugin_name, db_file_name=None):
|
|||||||
"""
|
"""
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
settings.beginGroup(plugin_name)
|
settings.beginGroup(plugin_name)
|
||||||
db_url = ''
|
|
||||||
db_type = settings.value('db type')
|
db_type = settings.value('db type')
|
||||||
if db_type == 'sqlite':
|
if db_type == 'sqlite':
|
||||||
if db_file_name is None:
|
db_url = get_db_path(plugin_name, db_file_name)
|
||||||
db_url = 'sqlite:///%s/%s.sqlite' % (AppLocation.get_section_data_path(plugin_name), plugin_name)
|
|
||||||
else:
|
|
||||||
db_url = 'sqlite:///%s/%s' % (AppLocation.get_section_data_path(plugin_name), db_file_name)
|
|
||||||
else:
|
else:
|
||||||
db_url = '%s://%s:%s@%s/%s' % (db_type, urlquote(settings.value('db username')),
|
db_url = '%s://%s:%s@%s/%s' % (db_type, urlquote(settings.value('db username')),
|
||||||
urlquote(settings.value('db password')),
|
urlquote(settings.value('db password')),
|
||||||
@ -212,7 +237,7 @@ class Manager(object):
|
|||||||
try:
|
try:
|
||||||
db_ver, up_ver = upgrade_db(self.db_url, upgrade_mod)
|
db_ver, up_ver = upgrade_db(self.db_url, upgrade_mod)
|
||||||
except (SQLAlchemyError, DBAPIError):
|
except (SQLAlchemyError, DBAPIError):
|
||||||
log.exception('Error loading database: %s', self.db_url)
|
handle_db_error(plugin_name, db_file_name)
|
||||||
return
|
return
|
||||||
if db_ver > up_ver:
|
if db_ver > up_ver:
|
||||||
critical_error_message_box(
|
critical_error_message_box(
|
||||||
@ -225,10 +250,7 @@ class Manager(object):
|
|||||||
try:
|
try:
|
||||||
self.session = init_schema(self.db_url)
|
self.session = init_schema(self.db_url)
|
||||||
except (SQLAlchemyError, DBAPIError):
|
except (SQLAlchemyError, DBAPIError):
|
||||||
log.exception('Error loading database: %s', self.db_url)
|
handle_db_error(plugin_name, db_file_name)
|
||||||
critical_error_message_box(translate('OpenLP.Manager', 'Database Error'),
|
|
||||||
translate('OpenLP.Manager', 'OpenLP cannot load your database.\n\nDatabase: %s')
|
|
||||||
% self.db_url)
|
|
||||||
|
|
||||||
def save_object(self, object_instance, commit=True):
|
def save_object(self, object_instance, commit=True):
|
||||||
"""
|
"""
|
||||||
@ -362,6 +384,8 @@ class Manager(object):
|
|||||||
:param object_class: The type of objects to return.
|
:param object_class: The type of objects to return.
|
||||||
:param filter_clause: The filter governing selection of objects to return. Defaults to None.
|
:param filter_clause: The filter governing selection of objects to return. Defaults to None.
|
||||||
"""
|
"""
|
||||||
|
if not self.session:
|
||||||
|
return
|
||||||
query = self.session.query(object_class)
|
query = self.session.query(object_class)
|
||||||
if filter_clause is not None:
|
if filter_clause is not None:
|
||||||
query = query.filter(filter_clause)
|
query = query.filter(filter_clause)
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
"""
|
"""
|
||||||
This module contains the first time wizard.
|
This module contains the first time wizard.
|
||||||
"""
|
"""
|
||||||
|
import hashlib
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
@ -221,8 +222,9 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
|
|||||||
self.application.process_events()
|
self.application.process_events()
|
||||||
title = self.config.get('songs_%s' % song, 'title')
|
title = self.config.get('songs_%s' % song, 'title')
|
||||||
filename = self.config.get('songs_%s' % song, 'filename')
|
filename = self.config.get('songs_%s' % song, 'filename')
|
||||||
|
sha256 = self.config.get('songs_%s' % song, 'sha256', fallback=None)
|
||||||
item = QtGui.QListWidgetItem(title, self.songs_list_widget)
|
item = QtGui.QListWidgetItem(title, self.songs_list_widget)
|
||||||
item.setData(QtCore.Qt.UserRole, filename)
|
item.setData(QtCore.Qt.UserRole, (filename, sha256))
|
||||||
item.setCheckState(QtCore.Qt.Unchecked)
|
item.setCheckState(QtCore.Qt.Unchecked)
|
||||||
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
|
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
|
||||||
bible_languages = self.config.get('bibles', 'languages')
|
bible_languages = self.config.get('bibles', 'languages')
|
||||||
@ -372,7 +374,7 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
|
|||||||
Settings().setValue('core/has run wizard', True)
|
Settings().setValue('core/has run wizard', True)
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
def url_get_file(self, url, f_path):
|
def url_get_file(self, url, f_path, sha256=None):
|
||||||
""""
|
""""
|
||||||
Download a file given a URL. The file is retrieved in chunks, giving the ability to cancel the download at any
|
Download a file given a URL. The file is retrieved in chunks, giving the ability to cancel the download at any
|
||||||
point. Returns False on download error.
|
point. Returns False on download error.
|
||||||
@ -396,7 +398,11 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
|
|||||||
block_count += 1
|
block_count += 1
|
||||||
self._download_progress(block_count, block_size)
|
self._download_progress(block_count, block_size)
|
||||||
filename.close()
|
filename.close()
|
||||||
except ConnectionError:
|
if sha256 and hashlib.sha256(open(f_path, 'rb').read()).hexdigest() != sha256:
|
||||||
|
log.error('sha256 sums did not match for file: {}'.format(f_path))
|
||||||
|
os.remove(f_path)
|
||||||
|
return False
|
||||||
|
except urllib.error.URLError:
|
||||||
trace_error_handler(log)
|
trace_error_handler(log)
|
||||||
filename.close()
|
filename.close()
|
||||||
os.remove(f_path)
|
os.remove(f_path)
|
||||||
@ -436,7 +442,7 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
|
|||||||
site = urllib.request.urlopen(url, timeout=CONNECTION_TIMEOUT)
|
site = urllib.request.urlopen(url, timeout=CONNECTION_TIMEOUT)
|
||||||
meta = site.info()
|
meta = site.info()
|
||||||
return int(meta.get("Content-Length"))
|
return int(meta.get("Content-Length"))
|
||||||
except ConnectionException:
|
except urllib.error.URLError:
|
||||||
if retries > CONNECTION_RETRIES:
|
if retries > CONNECTION_RETRIES:
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
@ -478,7 +484,7 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
|
|||||||
self.application.process_events()
|
self.application.process_events()
|
||||||
item = self.songs_list_widget.item(i)
|
item = self.songs_list_widget.item(i)
|
||||||
if item.checkState() == QtCore.Qt.Checked:
|
if item.checkState() == QtCore.Qt.Checked:
|
||||||
filename = item.data(QtCore.Qt.UserRole)
|
filename, _ = item.data(QtCore.Qt.UserRole)
|
||||||
size = self._get_file_size('%s%s' % (self.songs_url, filename))
|
size = self._get_file_size('%s%s' % (self.songs_url, filename))
|
||||||
self.max_progress += size
|
self.max_progress += size
|
||||||
# Loop through the Bibles list and increase for each selected item
|
# Loop through the Bibles list and increase for each selected item
|
||||||
@ -499,7 +505,7 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
|
|||||||
filename = item.data(QtCore.Qt.UserRole)
|
filename = item.data(QtCore.Qt.UserRole)
|
||||||
size = self._get_file_size('%s%s' % (self.themes_url, filename))
|
size = self._get_file_size('%s%s' % (self.themes_url, filename))
|
||||||
self.max_progress += size
|
self.max_progress += size
|
||||||
except ConnectionError:
|
except urllib.error.URLError:
|
||||||
trace_error_handler(log)
|
trace_error_handler(log)
|
||||||
critical_error_message_box(translate('OpenLP.FirstTimeWizard', 'Download Error'),
|
critical_error_message_box(translate('OpenLP.FirstTimeWizard', 'Download Error'),
|
||||||
translate('OpenLP.FirstTimeWizard', 'There was a connection problem during '
|
translate('OpenLP.FirstTimeWizard', 'There was a connection problem during '
|
||||||
@ -595,11 +601,11 @@ class FirstTimeForm(QtGui.QWizard, UiFirstTimeWizard, RegistryProperties):
|
|||||||
for i in range(self.songs_list_widget.count()):
|
for i in range(self.songs_list_widget.count()):
|
||||||
item = self.songs_list_widget.item(i)
|
item = self.songs_list_widget.item(i)
|
||||||
if item.checkState() == QtCore.Qt.Checked:
|
if item.checkState() == QtCore.Qt.Checked:
|
||||||
filename = item.data(QtCore.Qt.UserRole)
|
filename, sha256 = item.data(QtCore.Qt.UserRole)
|
||||||
self._increment_progress_bar(self.downloading % filename, 0)
|
self._increment_progress_bar(self.downloading % filename, 0)
|
||||||
self.previous_size = 0
|
self.previous_size = 0
|
||||||
destination = os.path.join(songs_destination, str(filename))
|
destination = os.path.join(songs_destination, str(filename))
|
||||||
if not self.url_get_file('%s%s' % (self.songs_url, filename), destination):
|
if not self.url_get_file('%s%s' % (self.songs_url, filename), destination, sha256):
|
||||||
return False
|
return False
|
||||||
# Download Bibles
|
# Download Bibles
|
||||||
bibles_iterator = QtGui.QTreeWidgetItemIterator(self.bibles_tree_widget)
|
bibles_iterator = QtGui.QTreeWidgetItemIterator(self.bibles_tree_widget)
|
||||||
|
@ -144,8 +144,9 @@ class BibleDB(QtCore.QObject, Manager, RegistryProperties):
|
|||||||
if 'file' in kwargs:
|
if 'file' in kwargs:
|
||||||
self.file = kwargs['file']
|
self.file = kwargs['file']
|
||||||
Manager.__init__(self, 'bibles', init_schema, self.file, upgrade)
|
Manager.__init__(self, 'bibles', init_schema, self.file, upgrade)
|
||||||
if 'file' in kwargs:
|
if self.session:
|
||||||
self.get_name()
|
if 'file' in kwargs:
|
||||||
|
self.get_name()
|
||||||
if 'path' in kwargs:
|
if 'path' in kwargs:
|
||||||
self.path = kwargs['path']
|
self.path = kwargs['path']
|
||||||
self.wizard = None
|
self.wizard = None
|
||||||
|
@ -121,6 +121,8 @@ class BibleManager(RegistryProperties):
|
|||||||
self.old_bible_databases = []
|
self.old_bible_databases = []
|
||||||
for filename in files:
|
for filename in files:
|
||||||
bible = BibleDB(self.parent, path=self.path, file=filename)
|
bible = BibleDB(self.parent, path=self.path, file=filename)
|
||||||
|
if not bible.session:
|
||||||
|
continue
|
||||||
name = bible.get_name()
|
name = bible.get_name()
|
||||||
# Remove corrupted files.
|
# Remove corrupted files.
|
||||||
if name is None:
|
if name is None:
|
||||||
|
Loading…
Reference in New Issue
Block a user