Better handle failed downloads

This commit is contained in:
Phill Ridout 2015-01-31 21:52:02 +00:00
parent 121f0908a1
commit 6d2b1d958e
4 changed files with 53 additions and 20 deletions

View File

@ -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)

View File

@ -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)

View File

@ -144,6 +144,7 @@ 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 self.session:
if 'file' in kwargs: if 'file' in kwargs:
self.get_name() self.get_name()
if 'path' in kwargs: if 'path' in kwargs:

View File

@ -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: