Skip to content

Commit

Permalink
Fix dictionaries being downloaded too late
Browse files Browse the repository at this point in the history
This commit fixes the dictionaries being downloaded too late causing
electron to use the default fallback download url.
  • Loading branch information
murilopereirame committed Apr 25, 2024
1 parent a64edf6 commit 7e5e6ab
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 50 deletions.
32 changes: 8 additions & 24 deletions src/desktop/ApplicationWindow.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { BrowserWindow, ContextMenuParams, NativeImage, Result, Session } from "electron"
import type { BrowserWindow, ContextMenuParams, NativeImage, Result } from "electron"
import type { WindowBounds, WindowManager } from "./DesktopWindowManager"
import url from "node:url"
import type { lazy } from "@tutao/tutanota-utils"
Expand Down Expand Up @@ -73,7 +73,6 @@ export class ApplicationWindow {
private readonly localShortcut: LocalShortcutManager,
private readonly themeFacade: DesktopThemeFacade,
private readonly remoteBridge: RemoteBridge,
dictUrl: string,
noAutoLogin?: boolean | null,
preloadOverridePath?: string,
) {
Expand Down Expand Up @@ -169,7 +168,6 @@ export class ApplicationWindow {
this.createBrowserWindow(wm, {
preloadPath,
icon,
dictUrl,
})
this.initFacades()

Expand Down Expand Up @@ -268,10 +266,10 @@ export class ApplicationWindow {
opts: {
preloadPath: string
icon: NativeImage
dictUrl: string
},
) {
const { preloadPath, dictUrl, icon } = opts
const { preloadPath, icon } = opts

this._browserWindow = new this.electron.BrowserWindow({
icon,
show: false,
Expand Down Expand Up @@ -299,6 +297,11 @@ export class ApplicationWindow {
},
})

const session = this._browserWindow.webContents.session
session.setPermissionRequestHandler((webContents, permission, callback: (_: boolean) => void) => callback(false))

handleProtocols(session, this.absoluteAssetsPath)

this._browserWindow.setMenuBarVisibility(false)

this._browserWindow.removeMenu()
Expand All @@ -307,13 +310,6 @@ export class ApplicationWindow {

this.id = this._browserWindow.id

const session = this._browserWindow.webContents.session
session.setPermissionRequestHandler((webContents, permission, callback: (_: boolean) => void) => callback(false))

handleProtocols(session, this.absoluteAssetsPath)

this.manageDownloadsForSession(session, dictUrl)

this._browserWindow
.on("closed", async () => {
await this.closeDb()
Expand Down Expand Up @@ -484,18 +480,6 @@ export class ApplicationWindow {
this._desktopFacade.addShortcuts(webShortcuts)
}

private manageDownloadsForSession(session: Session, dictUrl: string) {
dictUrl = dictUrl + "/dictionaries/"
log.debug(TAG, "getting dictionaries from:", dictUrl)
session.setSpellCheckerDictionaryDownloadURL(dictUrl)
session
.removeAllListeners("spellcheck-dictionary-download-failure")
.on("spellcheck-dictionary-initialized", (ev, lcode) => log.debug(TAG, "spellcheck-dictionary-initialized", lcode))
.on("spellcheck-dictionary-download-begin", (ev, lcode) => log.debug(TAG, "spellcheck-dictionary-download-begin", lcode))
.on("spellcheck-dictionary-download-success", (ev, lcode) => log.debug(TAG, "spellcheck-dictionary-download-success", lcode))
.on("spellcheck-dictionary-download-failure", (ev, lcode) => log.debug(TAG, "spellcheck-dictionary-download-failure", lcode))
}

private tryGoBack(): void {
const parsedUrl = url.parse(this._browserWindow.webContents.getURL())

Expand Down
22 changes: 21 additions & 1 deletion src/desktop/DesktopMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { mp } from "./DesktopMonkeyPatch"
import { err } from "./DesktopErrorHandler"
import { DesktopConfig } from "./config/DesktopConfig"
import * as electron from "electron"
import { app } from "electron"
import { app, type Session } from "electron"
import { DesktopUtils } from "./DesktopUtils"
import { setupAssetProtocol, WindowManager } from "./DesktopWindowManager"
import { DesktopNotifier } from "./DesktopNotifier"
Expand Down Expand Up @@ -73,6 +73,8 @@ dns.setDefaultResultOrder("ipv4first")

setupAssetProtocol(electron)

const TAG = "[DesktopMain]"

mp()
type Components = {
readonly wm: WindowManager
Expand Down Expand Up @@ -189,6 +191,12 @@ async function createComponents(): Promise<Components> {
}

const offlineDbRefCounter = new OfflineDbRefCounter(offlineDbFactory)
const updateUrl = await conf.getConst(BuildConfigKey.updateUrl)
const dictUrl = updateUrl ? updateUrl : "https://app.tuta.com/desktop/"

electron.app.on("session-created", async (session) => {
manageDownloadsForSession(session, dictUrl)
})

const wm = new WindowManager(conf, tray, notifier, electron, shortcutManager, appIcon)
const themeFacade = new DesktopThemeFacade(conf, wm, electron.nativeTheme)
Expand Down Expand Up @@ -339,3 +347,15 @@ async function main(components: Components) {
integrator.runIntegration(wm)
await desktopUtils.handleMailto(components.wm)
}

function manageDownloadsForSession(session: Session, dictUrl: string) {
dictUrl = dictUrl + "/dictionaries/"
log.debug(TAG, "getting dictionaries from:", dictUrl)
session.setSpellCheckerDictionaryDownloadURL(dictUrl)
session
.removeAllListeners("spellcheck-dictionary-download-failure")
.on("spellcheck-dictionary-initialized", (ev, lcode) => log.debug(TAG, "spellcheck-dictionary-initialized", lcode))
.on("spellcheck-dictionary-download-begin", (ev, lcode) => log.debug(TAG, "spellcheck-dictionary-download-begin", lcode))
.on("spellcheck-dictionary-download-success", (ev, lcode) => log.debug(TAG, "spellcheck-dictionary-download-success", lcode))
.on("spellcheck-dictionary-download-failure", (ev, lcode) => log.debug(TAG, "spellcheck-dictionary-download-failure", lcode))
}
3 changes: 0 additions & 3 deletions src/desktop/DesktopWindowManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,6 @@ export class WindowManager {

private async _newWindow(electron: ElectronExports, localShortcut: LocalShortcutManager, noAutoLogin: boolean | null): Promise<ApplicationWindow> {
const absoluteWebAssetsPath = this._electron.app.getAppPath()
const updateUrl = await this._conf.getConst(BuildConfigKey.updateUrl)
const dictUrl = updateUrl && updateUrl !== "" ? updateUrl : "https://app.tuta.com/desktop/"
// custom builds get the dicts from us as well
return new ApplicationWindow(
this,
Expand All @@ -294,7 +292,6 @@ export class WindowManager {
localShortcut,
this.themeFacade,
this.remoteBridge,
dictUrl,
noAutoLogin,
this.preloadOverride,
)
Expand Down
41 changes: 19 additions & 22 deletions test/tests/desktop/ApplicationWindowTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import BrowserWindow = Electron.BrowserWindow

const { anything } = matchers

const dictUrl = "dictUrl"
o.spec("ApplicationWindow Test", function () {
const electronLocalshortcut = {
callbacks: Object.create(null),
Expand Down Expand Up @@ -304,7 +303,7 @@ o.spec("ApplicationWindow Test", function () {

o("construction", async function () {
const { electronMock, wmMock, electronLocalshortcutMock, themeFacade, remoteBridge } = standardMocks()
const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge, dictUrl)
const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge)
o(electronMock.BrowserWindow.mockedInstances.length).equals(1)
const bwInstance: BrowserWindow = electronMock.BrowserWindow.mockedInstances[0]
// We load some things async before loading URL so we wait for it. __loadedUrl comes from our mock
Expand Down Expand Up @@ -346,8 +345,6 @@ o.spec("ApplicationWindow Test", function () {
o(bwInstance.setMenuBarVisibility.callCount).equals(1)
o(bwInstance.setMenuBarVisibility.args[0]).equals(false)
o(bwInstance.removeMenu.callCount).equals(1)
o(bwInstance.webContents.session.setSpellCheckerDictionaryDownloadURL.callCount).equals(1)
o(bwInstance.webContents.session.setSpellCheckerDictionaryDownloadURL.args[0]).equals(dictUrl + "/dictionaries/")
o(Object.keys((bwInstance.webContents as any).callbacks)).deepEquals([
"will-attach-webview",
"will-navigate",
Expand All @@ -369,7 +366,7 @@ o.spec("ApplicationWindow Test", function () {
o("construction, noAutoLogin", async function () {
const { electronMock, wmMock, electronLocalshortcutMock, themeFacade, remoteBridge } = standardMocks()
// noAutoLogin=true
const w2 = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge, dictUrl, true)
const w2 = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge, true)
const bwInstance2 = electronMock.BrowserWindow.mockedInstances[0]
await bwInstance2.__loadedUrl.promise
o(bwInstance2.loadURL.callCount).equals(1)
Expand All @@ -382,7 +379,7 @@ o.spec("ApplicationWindow Test", function () {

o("redirect to start page after failing to load a page due to 404", async function () {
const { wmMock, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge } = standardMocks()
const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge, dictUrl)
const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge)
const bwInstance = electronMock.BrowserWindow.mockedInstances[0]
await bwInstance.__loadedUrl.promise
bwInstance.__loadedUrl = defer()
Expand All @@ -402,7 +399,7 @@ o.spec("ApplicationWindow Test", function () {
n.setPlatform("linux")
const { electronLocalshortcutMock, wmMock, electronMock, themeFacade, remoteBridge } = standardMocks()

const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge, dictUrl)
const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge)
downcast(w._browserWindow.webContents).callbacks["did-finish-load"]()
o(Object.keys(electronLocalshortcutMock.callbacks)).deepEquals([
"Control+F",
Expand All @@ -420,7 +417,7 @@ o.spec("ApplicationWindow Test", function () {
o("shortcut creation, windows", function () {
n.setPlatform("win32")
const { electronLocalshortcutMock, wmMock, electronMock, themeFacade, remoteBridge } = standardMocks()
const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge, dictUrl)
const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge)
downcast(w._browserWindow.webContents).callbacks["did-finish-load"]()
o(Object.keys(electronLocalshortcutMock.callbacks)).deepEquals([
"Control+F",
Expand All @@ -439,7 +436,7 @@ o.spec("ApplicationWindow Test", function () {
n.setPlatform("darwin")
const { electronLocalshortcutMock, wmMock, electronMock, themeFacade, remoteBridge } = standardMocks()

const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge, dictUrl)
const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge)
downcast(w._browserWindow.webContents).callbacks["did-finish-load"]()
o(Object.keys(electronLocalshortcutMock.callbacks)).deepEquals(["Command+F", "Command+P", "F12", "Command+0", "Command+Q", "Command+Control+F"])
})
Expand All @@ -449,7 +446,7 @@ o.spec("ApplicationWindow Test", function () {
const sm = standardMocks()
const { electronMock, electronLocalshortcutMock, wmMock, themeFacade, remoteBridge } = sm

const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge, dictUrl)
const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge)
const bwInstance = electronMock.BrowserWindow.mockedInstances[0]
;(bwInstance.webContents as any).callbacks["did-finish-load"]()
// ApplicationWindow waits for IPC and this is a reliable way to also wait for it
Expand Down Expand Up @@ -536,7 +533,7 @@ o.spec("ApplicationWindow Test", function () {
n.setPlatform("linux")
const { electronMock, electronLocalshortcutMock, wmMock, themeFacade, remoteBridge, desktopFacade } = standardMocks()

const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge, dictUrl)
const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge)
const bwInstance = electronMock.BrowserWindow.mockedInstances[0]
bwInstance.webContents.callbacks["did-finish-load"]()
verify(desktopFacade.addShortcuts(anything()))
Expand All @@ -558,7 +555,7 @@ o.spec("ApplicationWindow Test", function () {
const e = {
preventDefault: spy(),
}
const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge, dictUrl)
const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge)
const bwInstance = electronMock.BrowserWindow.mockedInstances[0]
bwInstance.webContents.callbacks["will-navigate"](e, "http://test.com")
o(e.preventDefault.callCount).equals(1)("Prevent default is called")
Expand All @@ -567,7 +564,7 @@ o.spec("ApplicationWindow Test", function () {
o("attaching webView is denied", function () {
const { electronMock, wmMock, electronLocalshortcutMock, themeFacade, remoteBridge } = standardMocks()

const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge, dictUrl)
const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge)
const bwInstance = electronMock.BrowserWindow.mockedInstances[0]
const e = {
preventDefault: spy(),
Expand All @@ -593,7 +590,7 @@ o.spec("ApplicationWindow Test", function () {
electronMock = sm.electronMock
let { wmMock, electronLocalshortcutMock, themeFacade, remoteBridge } = sm

new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge, dictUrl)
new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge)
bwInstance = electronMock.BrowserWindow.mockedInstances[0]
})
o("not url is not redirected", function () {
Expand Down Expand Up @@ -658,7 +655,7 @@ o.spec("ApplicationWindow Test", function () {
o("context-menu is passed to handler", function () {
const { electronMock, wmMock, electronLocalshortcutMock, themeFacade, remoteBridge } = standardMocks()

const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge, dictUrl)
const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge)
const handlerMock = n.spyify(() => {})
w.setContextMenuHandler(handlerMock)
const bwInstance = electronMock.BrowserWindow.mockedInstances[0]
Expand All @@ -682,7 +679,7 @@ o.spec("ApplicationWindow Test", function () {
o("openMailbox sends mailbox info and shows window", async function () {
const { electronMock, wmMock, electronLocalshortcutMock, themeFacade, remoteBridge, commonNativeFacade } = standardMocks()

const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge, dictUrl)
const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge)
w.openMailBox(
{
userId: "userId",
Expand All @@ -699,7 +696,7 @@ o.spec("ApplicationWindow Test", function () {
n.setPlatform("linux")
const { electronMock, wmMock, electronLocalshortcutMock, themeFacade, remoteBridge } = standardMocks()

const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge, dictUrl)
const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge)
o(w.getBounds()).deepEquals({
rect: {
height: 0,
Expand Down Expand Up @@ -784,7 +781,7 @@ o.spec("ApplicationWindow Test", function () {
o("findInPage, setSearchOverlayState & stopFindInPage", function () {
const { electronMock, wmMock, electronLocalshortcutMock, themeFacade, remoteBridge } = standardMocks()

const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge, dictUrl)
const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge)
const wcMock = electronMock.BrowserWindow.mockedInstances[0].webContents
w.stopFindInPage()
o(wcMock.stopFindInPage.callCount).equals(1)
Expand Down Expand Up @@ -839,7 +836,7 @@ o.spec("ApplicationWindow Test", function () {
o("show", function () {
const { electronMock, wmMock, electronLocalshortcutMock, themeFacade, remoteBridge } = standardMocks()

const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge, dictUrl)
const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge)
const bwMock = electronMock.BrowserWindow.mockedInstances[0]
o(bwMock.devToolsOpened).equals(false)
w.show()
Expand Down Expand Up @@ -870,7 +867,7 @@ o.spec("ApplicationWindow Test", function () {
o("on, once, getTitle, setZoomFactor, isFullScreen, isMinimized, minimize, hide, center, showInactive, isFocused", function () {
const { electronMock, wmMock, electronLocalshortcutMock, themeFacade, remoteBridge } = standardMocks()

const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge, dictUrl)
const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge)
const bwInstance = electronMock.BrowserWindow.mockedInstances[0]

let f = () => {}
Expand Down Expand Up @@ -908,7 +905,7 @@ o.spec("ApplicationWindow Test", function () {
o("when closing, database is closed", function () {
const { electronMock, wmMock, electronLocalshortcutMock, themeFacade, remoteBridge, sqlCipherFacade } = standardMocks()

const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge, dictUrl)
const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge)
const userId = "123"
w.setUserId(userId)
const bwInstance = electronMock.BrowserWindow.mockedInstances[0]
Expand All @@ -920,7 +917,7 @@ o.spec("ApplicationWindow Test", function () {
o("when reloading, database is closed", async function () {
const { electronMock, wmMock, electronLocalshortcutMock, themeFacade, remoteBridge, sqlCipherFacade } = standardMocks()

const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge, dictUrl)
const w = new ApplicationWindow(wmMock, desktopHtml, icon, electronMock, electronLocalshortcutMock, themeFacade, remoteBridge)
const userId = "123"
w.setUserId(userId)

Expand Down

0 comments on commit 7e5e6ab

Please sign in to comment.