Load the db early during initialization

This commit is contained in:
Kovid Goyal 2017-01-24 07:03:00 +05:30
parent b99e261260
commit 09717b15c4
6 changed files with 120 additions and 47 deletions

View File

@ -21,3 +21,15 @@ def get_current_query(newval):
if newval:
get_current_query.ans = newval
return get_current_query.ans
def get_db(db):
if db:
get_db.db = db
return get_db.db
def get_translations(val):
if val:
get_translations.ans = val
return get_translations.ans

View File

@ -14,8 +14,10 @@ from utils import parse_url_params
from book_list.constants import book_list_container_id, read_book_container_id
from book_list.theme import get_color
from book_list.router import update_window_title, set_default_mode_handler, apply_url
from book_list.router import update_window_title, set_default_mode_handler, apply_url, set_mode_handler
from book_list.globals import get_db, set_session_data
from book_list.ui import apply_url_state as book_list_mode_handler
from read_book.ui import ReadUI
# Register the various panels
import book_list.home # noqa: unused-import
@ -39,13 +41,17 @@ def onerror(msg, script_url, line_number, column_number, error_object):
except:
console.log('There was an error in the unhandled exception handler')
read_ui = None
def init_ui():
nonlocal read_ui
install_event_filters()
set_default_mode_handler(book_list_mode_handler)
window.onerror = onerror
translations = get_translations()
if translations:
install(translations)
get_translations(translations)
remove_initial_progress_bar()
document.head.appendChild(E.style(get_widget_css()))
set_css(document.body, background_color=get_color('window-background'), color=get_color('window-foreground'))
@ -54,6 +60,9 @@ def init_ui():
document.body.lastChild.appendChild(E.div(id=read_book_container_id, style='display: none'))
create_modal_container()
update_window_title()
read_ui = ReadUI()
get_db(read_ui.db)
set_mode_handler('read_book', read_ui.apply_url_state.bind(read_ui))
apply_url()
def on_data_loaded(end_type, xhr, ev):
@ -61,6 +70,9 @@ def on_data_loaded(end_type, xhr, ev):
if end_type is 'load':
data = JSON.parse(xhr.responseText)
update_interface_data(data)
interface_data = get_interface_data()
sd = UserSessionData(interface_data.username, interface_data.user_session_data)
set_session_data(sd)
if data.translations:
get_translations(data.translations)
init_ui()
@ -94,4 +106,7 @@ def main():
if get_interface_data().is_default:
load_interface_data()
else:
interface_data = get_interface_data()
sd = UserSessionData(interface_data.username, interface_data.user_session_data)
set_session_data(sd)
init_ui()

View File

@ -8,6 +8,7 @@ from utils import parse_url_params
mode_handlers = {}
default_mode_handler = None
read_book_mode = 'read_book'
def set_mode_handler(mode, handler):
@ -24,8 +25,13 @@ def update_window_title(subtitle, title='calibre', sep=' :: '):
document.title = title + extra
def is_reading_book():
cq = get_current_query
return cq and cq.mode is read_book_mode
def apply_mode(mode):
divid = read_book_container_id if (mode or get_current_query().mode) is 'read_book' else book_list_container_id
divid = read_book_container_id if is_reading_book() else book_list_container_id
for div in document.getElementById(divid).parentNode.childNodes:
div.style.display = 'block' if div.id is divid else 'none'
@ -37,3 +43,10 @@ def apply_url():
apply_mode()
handler = mode_handlers[data.mode] or default_mode_handler
handler(data)
def push_state(query, replace=False, mode='book_list'):
query = {k:query[k] for k in query}
if mode is not 'book_list':
query.mode = mode
# TODO: Implement this (see push_state in boos.pyj)

View File

@ -1,9 +1,12 @@
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
from __python__ import hash_literals
from __python__ import hash_literals, bound_methods
from gettext import gettext as _
from encodings import base64encode, base64decode
from modals import error_dialog
from book_list.router import is_reading_book
def upgrade_schema(idb, old_version, new_version):
print('upgrade_schema:', old_version, new_version)
@ -31,13 +34,59 @@ DB_VERSION = 2
class DB:
def __init__(self, idb, ui, supports_blobs):
self.interface_data = ui.interface_data
def __init__(self, callback, show_read_book_error):
self.initialized = False
self.initialize_error_msg = None
self.callback = callback
self.show_read_book_error = show_read_book_error
self.initialize_stage1()
def show_error(self, title, msg, det_msg):
if is_reading_book():
self.show_read_book_error(title, msg, det_msg)
else:
error_dialog(title, msg, det_msg)
def initialize_stage1(self):
if not window.indexedDB:
self.initialize_error_msg = _('Your browser does not support IndexedDB. Cannot read books. Consider using a modern browser, such as Firefox, Chrome or Edge.')
self.initialized = True
self.callback()
return
request = window.indexedDB.open(DB_NAME, DB_VERSION)
request.onupgradeneeded = def(event):
upgrade_schema(event.target.result, event.oldVersion, event.newVersion)
request.onblocked = def(event):
self.initialize_error_msg = _('Please close all other browser tabs with calibre open')
self.initialized = True
self.callback()
request.onerror = def(event):
self.initialize_error_msg = _('You must allow calibre to use IndexedDB storage in your browser to read books')
self.initialized = True
self.callback()
request.onsuccess = def(event):
blob = Blob(['test'], {'type':"text/plain"})
idb = event.target.result
try:
req = idb.transaction(['files'], 'readwrite').objectStore('files').put(blob, ':-test-blob-:')
except Exception:
self.initialize_stage2(idb, False)
req.onsuccess = def(event):
self.initialize_stage2(idb, True)
req.onerror = def(event):
self.initialize_stage2(idb, False)
def initialize_stage2(self, idb, supports_blobs):
self.idb = idb
self.supports_blobs = supports_blobs
self.initialized = True
if not supports_blobs:
print('IndexedDB does not support Blob storage, using base64 encoding instead')
self.show_error = ui.show_error.bind(ui)
print('WARNING: browser does not support blob storage, calibre falling back to base64 encoding')
idb.onerror = def(event):
self.display_error(None, event)
@ -48,8 +97,9 @@ class DB:
idb.onversionchange = def(event):
idb.close()
ui.show_error(_('Database upgraded!'), _(
self.show_error(_('Database upgraded!'), _(
'A newer version of calibre is available, please click the reload button in your browser.'))
self.callback()
def display_error(self, msg, event):
if event.already_displayed_by_calibre:
@ -225,31 +275,8 @@ class DB:
books.delete(book.key)
next_step()
def create_db(ui, interface_data):
if not window.indexedDB:
return ui.db_initialized(_('Your browser does not support IndexedDB. Cannot read books. Consider using a modern browser, such as Firefox, Chrome or Edge.'))
request = window.indexedDB.open(DB_NAME, DB_VERSION)
request.onupgradeneeded = def(event):
upgrade_schema(event.target.result, event.oldVersion, event.newVersion)
request.onblocked = def(event):
alert(_('Please close all other tabs with a calibre book open'))
request.onerror = def(event):
ui.db_initialized(_('You must allow calibre to use IndexedDB storage in your browser to read books'))
request.onsuccess = def(event):
blob = Blob(['test'], {'type':"text/plain"})
idb = event.target.result
try:
req = idb.transaction(['files'], 'readwrite').objectStore('files').put(blob, ':-test-blob-:')
except Exception:
print('WARNING: browser does not support blob storage, calibre falling back to base64 encoding')
return ui.db_initialized(DB(idb, ui, False))
req.onsuccess = def(event):
ui.db_initialized(DB(idb, ui, True))
req.onerror = def(event):
print('WARNING: browser does not support blob storage, calibre falling back to base64 encoding')
ui.db_initialized(DB(idb, ui, False))
def get_db(callback, show_read_book_error):
if not get_db.ans:
get_db.ans = DB(callback)
return get_db.ans

View File

@ -10,8 +10,9 @@ from gettext import gettext as _
from modals import error_dialog
from utils import human_readable, debounce
from book_list.constants import read_book_container_id
from read_book.db import get_db
from book_list.router import update_window_title
from read_book.db import create_db
from read_book.view import View
RENDER_VERSION = __RENDER_VERSION__
@ -19,19 +20,17 @@ MATHJAX_VERSION = "__MATHJAX_VERSION__"
class ReadUI:
def __init__(self, interface_data, container):
self.interface_data = interface_data
self.db = None
def __init__(self):
self.current_metadata = {'title': _('Unknown book')}
self.current_book_id = None
self.manifest_xhr = None
create_db(self, interface_data)
self.pending_load = None
self.downloads_in_progress = []
self.progress_id = 'book-load-progress'
self.display_id = 'book-iframe-container'
self.error_id = 'book-global-error-container'
self.stacked_widgets = [self.progress_id, self.display_id, self.error_id]
container = document.getElementById(read_book_container_id)
container.appendChild(E.div(
id=self.progress_id, style='display:none; text-align: center',
@ -51,6 +50,7 @@ class ReadUI:
))
self.view = View(container.lastChild, self)
window.addEventListener('resize', debounce(self.on_resize.bind(self), 250))
self.db = get_db(self.db_initialized.bind(self), self.show_error.bind(self))
def on_resize(self):
self.view.on_resize()
@ -99,7 +99,7 @@ class ReadUI:
def load_book(self, book_id, fmt, metadata, force_reload):
self.base_url_data = {'book_id':book_id, 'fmt':fmt}
if self.db is None:
if not self.db.initialized:
self.pending_load = [book_id, fmt, metadata, force_reload]
return
self.start_load(book_id, fmt, metadata, force_reload)
@ -126,10 +126,12 @@ class ReadUI:
ans.bookpos = bookpos
return ans
def db_initialized(self, db):
self.db = db
def db_initialized(self):
if self.pending_load is not None:
pl, self.pending_load = self.pending_load, None
if self.db.initialize_error_msg:
self.show_error(_('Failed to initialize IndexedDB'), self.db.initialize_error_msg)
else:
self.start_load(*pl)
def start_load(self, book_id, fmt, metadata, force_reload):
@ -402,3 +404,6 @@ class ReadUI:
def display_book_stage2(self, book):
self.show_stack(self.display_id)
self.view.display_book(book)
def apply_url_state(self, current_query):
pass

View File

@ -8,7 +8,8 @@ from gettext import gettext as _
from utils import html_escape
from modals import error_dialog, warning_dialog
from book_list.globals import get_session_data, get_boss, main_js
from book_list.globals import get_session_data, main_js, get_translations
from book_list.router import push_state, read_book_mode
from read_book.globals import messenger, iframe_id, current_book, set_current_spine_item
from read_book.resources import load_resources
from read_book.overlay import Overlay
@ -228,7 +229,7 @@ class View:
def on_iframe_ready(self, data):
messenger.reset()
self.send_message('initialize', secret=messenger.secret, translations=self.ui.interface_data.translations)
self.send_message('initialize', secret=messenger.secret, translations=get_translations())
self.iframe_ready = True
if self.pending_load:
data = self.pending_load
@ -354,7 +355,7 @@ class View:
def on_update_cfi(self, data):
self.currently_showing.bookpos = data.cfi
get_boss().push_state(replace=data.replace_history)
push_state(self.url_data, replace=data.replace_history, mode=read_book_mode)
unkey = username_key(self.ui.interface_data.username)
if not self.book.last_read_position:
self.book.last_read_position = {}