fix webviews sometimes failing to load, by enabling cache
Fixes #983 This has been a long-standing issue that was infrequent enough on developer machines that we weren't able to get to the bottom of it before now. As luck would have it, the new ARM build had just the right timing for this to occur every few invocations, and I was able to narrow it down to the call that turns off the cache. We don't really want the cache, so this is not a great solution. But I ran into trouble when trying to figure out a better solution: - Calling setHttpCacheType() earlier (eg immediately after creating the page) fails. - It even fails if you attempt to change the setting in the shared default profile before any webviews are loaded: ``` def setupMainWindow(self) -> None: QWebEngineProfile.defaultProfile().setHttpCacheType(QWebEngineProfile.HttpCacheType.NoCache) ``` - Creating a profile separately, and passing it into QWebEnginePage() does work. But it introduces a warning each time a webview is deallocated, and I fear it may lead to crashes: ``` Release of profile requested but WebEnginePage still not deleted. Expect troubles ! ``` I tried various combinations of parents for the profile and page, and turning web._page into an unretained property, but could not figure it out. Some Googling pulls up a bunch of other people who seem to have hit similar issues with PyQt. If anyone has any ideas, they'd be welcome; in the mean time, I guess we're better off using up some of the user's disk space than sometimes failing to load. The profile-in-advance code I tried is below: ``` diff --git a/qt/aqt/webview.py b/qt/aqt/webview.py index 1c96112d8..4f3e91284 100644 --- a/qt/aqt/webview.py +++ b/qt/aqt/webview.py @@ -23,9 +23,49 @@ serverbaseurl = re.compile(r"^.+:\/\/[^\/]+") BridgeCommandHandler = Callable[[str], Any] +def _create_profile(parent: QObject) -> QWebEngineProfile: + qwebchannel = ":/qtwebchannel/qwebchannel.js" + jsfile = QFile(qwebchannel) + if not jsfile.open(QIODevice.OpenModeFlag.ReadOnly): + print(f"Error opening '{qwebchannel}': {jsfile.error()}", file=sys.stderr) + jstext = bytes(cast(bytes, jsfile.readAll())).decode("utf-8") + jsfile.close() + + script = QWebEngineScript() + script.setSourceCode( + jstext + + """ + var pycmd, bridgeCommand; + new QWebChannel(qt.webChannelTransport, function(channel) { + bridgeCommand = pycmd = function (arg, cb) { + var resultCB = function (res) { + // pass result back to user-provided callback + if (cb) { + cb(JSON.parse(res)); + } + } + + channel.objects.py.cmd(arg, resultCB); + return false; + } + pycmd("domDone"); + }); + """ + ) + script.setWorldId(QWebEngineScript.ScriptWorldId.MainWorld) + script.setInjectionPoint(QWebEngineScript.InjectionPoint.DocumentReady) + script.setRunsOnSubFrames(False) + + profile = QWebEngineProfile(parent) + profile.setHttpCacheType(QWebEngineProfile.HttpCacheType.NoCache) + profile.scripts().insert(script) + return profile + + class AnkiWebPage(QWebEnginePage): - def __init__(self, onBridgeCmd: BridgeCommandHandler) -> None: - QWebEnginePage.__init__(self) + def __init__(self, onBridgeCmd: BridgeCommandHandler, parent: QObject) -> None: + profile = _create_profile(parent) + QWebEnginePage.__init__(self, profile, parent) self._onBridgeCmd = onBridgeCmd self._setupBridge() self.open_links_externally = True @@ -46,39 +86,6 @@ class AnkiWebPage(QWebEnginePage): self._channel.registerObject("py", self._bridge) self.setWebChannel(self._channel) - qwebchannel = ":/qtwebchannel/qwebchannel.js" - jsfile = QFile(qwebchannel) - if not jsfile.open(QIODevice.OpenModeFlag.ReadOnly): - print(f"Error opening '{qwebchannel}': {jsfile.error()}", file=sys.stderr) - jstext = bytes(cast(bytes, jsfile.readAll())).decode("utf-8") - jsfile.close() - - script = QWebEngineScript() - script.setSourceCode( - jstext - + """ - var pycmd, bridgeCommand; - new QWebChannel(qt.webChannelTransport, function(channel) { - bridgeCommand = pycmd = function (arg, cb) { - var resultCB = function (res) { - // pass result back to user-provided callback - if (cb) { - cb(JSON.parse(res)); - } - } - - channel.objects.py.cmd(arg, resultCB); - return false; - } - pycmd("domDone"); - }); - """ - ) - script.setWorldId(QWebEngineScript.ScriptWorldId.MainWorld) - script.setInjectionPoint(QWebEngineScript.InjectionPoint.DocumentReady) - script.setRunsOnSubFrames(False) - self.profile().scripts().insert(script) - def javaScriptConsoleMessage( self, level: QWebEnginePage.JavaScriptConsoleMessageLevel, @@ -228,7 +235,7 @@ class AnkiWebView(QWebEngineView): ) -> None: QWebEngineView.__init__(self, parent=parent) self.set_title(title) - self._page = AnkiWebPage(self._onBridgeCmd) + self._page = AnkiWebPage(self._onBridgeCmd, self) self._page.setBackgroundColor( self.get_window_bg_color(theme_manager.night_mode) @@ -242,7 +249,6 @@ class AnkiWebView(QWebEngineView): self.requiresCol = True self.setPage(self._page) - self._page.profile().setHttpCacheType(QWebEngineProfile.HttpCacheType.NoCache) self.resetHandlers() self.allowDrops = False self._filterSet = False ```
This commit is contained in:
parent
d87383a2d5
commit
db5117ce1a
@ -242,7 +242,6 @@ class AnkiWebView(QWebEngineView):
|
||||
self.requiresCol = True
|
||||
self.setPage(self._page)
|
||||
|
||||
self._page.profile().setHttpCacheType(QWebEngineProfile.HttpCacheType.NoCache)
|
||||
self.resetHandlers()
|
||||
self.allowDrops = False
|
||||
self._filterSet = False
|
||||
|
Loading…
Reference in New Issue
Block a user