Run SQL initialize in parallel with createWindow
This commit is contained in:
parent
af9e038add
commit
207d05fd05
5 changed files with 123 additions and 30 deletions
|
@ -71,7 +71,8 @@ window.Whisper.events = {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
try {
|
try {
|
||||||
window.log.info('Initializing SQL in renderer');
|
window.log.info('Initializing SQL in renderer');
|
||||||
await window.sqlInitializer.initialize();
|
const isTesting = true;
|
||||||
|
await window.sqlInitializer.initialize(isTesting);
|
||||||
window.log.info('SQL initialized in renderer');
|
window.log.info('SQL initialized in renderer');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
window.log.error(
|
window.log.error(
|
||||||
|
|
107
main.js
107
main.js
|
@ -133,14 +133,22 @@ const defaultWebPrefs = {
|
||||||
};
|
};
|
||||||
|
|
||||||
async function getSpellCheckSetting() {
|
async function getSpellCheckSetting() {
|
||||||
|
const fastValue = ephemeralConfig.get('spell-check');
|
||||||
|
if (fastValue !== undefined) {
|
||||||
|
console.log('got fast spellcheck setting', fastValue);
|
||||||
|
return fastValue;
|
||||||
|
}
|
||||||
|
|
||||||
const json = await sql.sqlCall('getItemById', ['spell-check']);
|
const json = await sql.sqlCall('getItemById', ['spell-check']);
|
||||||
|
|
||||||
// Default to `true` if setting doesn't exist yet
|
// Default to `true` if setting doesn't exist yet
|
||||||
if (!json) {
|
const slowValue = json ? json.value : true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return json.value;
|
ephemeralConfig.set('spell-check', slowValue);
|
||||||
|
|
||||||
|
console.log('got slow spellcheck setting', slowValue);
|
||||||
|
|
||||||
|
return slowValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
function showWindow() {
|
function showWindow() {
|
||||||
|
@ -316,7 +324,7 @@ if (OS.isWindows()) {
|
||||||
async function createWindow() {
|
async function createWindow() {
|
||||||
const { screen } = electron;
|
const { screen } = electron;
|
||||||
const windowOptions = {
|
const windowOptions = {
|
||||||
show: !startInTray, // allow to start minimised in tray
|
show: false,
|
||||||
width: DEFAULT_WIDTH,
|
width: DEFAULT_WIDTH,
|
||||||
height: DEFAULT_HEIGHT,
|
height: DEFAULT_HEIGHT,
|
||||||
minWidth: MIN_WIDTH,
|
minWidth: MIN_WIDTH,
|
||||||
|
@ -528,8 +536,44 @@ async function createWindow() {
|
||||||
mainWindow.on('leave-full-screen', () => {
|
mainWindow.on('leave-full-screen', () => {
|
||||||
mainWindow.webContents.send('full-screen-change', false);
|
mainWindow.webContents.send('full-screen-change', false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mainWindow.once('ready-to-show', async () => {
|
||||||
|
console.log('main window is ready-to-show');
|
||||||
|
|
||||||
|
try {
|
||||||
|
await sqlInitPromise;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(
|
||||||
|
'main window is ready, but sql has errored',
|
||||||
|
error && error.stack
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mainWindow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allow to start minimised in tray
|
||||||
|
if (!startInTray) {
|
||||||
|
console.log('showing main window');
|
||||||
|
mainWindow.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Renderer asks if we are done with the database
|
||||||
|
ipc.on('database-ready', async event => {
|
||||||
|
try {
|
||||||
|
await sqlInitPromise;
|
||||||
|
} catch (error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('sending `database-ready`');
|
||||||
|
event.sender.send('database-ready');
|
||||||
|
});
|
||||||
|
|
||||||
ipc.on('show-window', () => {
|
ipc.on('show-window', () => {
|
||||||
showWindow();
|
showWindow();
|
||||||
});
|
});
|
||||||
|
@ -960,6 +1004,29 @@ function showPermissionsPopupWindow(forCalling, forCamera) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function initializeSQL() {
|
||||||
|
const userDataPath = await getRealPath(app.getPath('userData'));
|
||||||
|
|
||||||
|
let key = userConfig.get('key');
|
||||||
|
if (!key) {
|
||||||
|
console.log(
|
||||||
|
'key/initialize: Generating new encryption key, since we did not find it on disk'
|
||||||
|
);
|
||||||
|
// https://www.zetetic.net/sqlcipher/sqlcipher-api/#key
|
||||||
|
key = crypto.randomBytes(32).toString('hex');
|
||||||
|
userConfig.set('key', key);
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlInitTimeStart = Date.now();
|
||||||
|
await sql.initialize({
|
||||||
|
configDir: userDataPath,
|
||||||
|
key,
|
||||||
|
});
|
||||||
|
sqlInitTimeEnd = Date.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
const sqlInitPromise = initializeSQL();
|
||||||
|
|
||||||
// This method will be called when Electron has finished
|
// This method will be called when Electron has finished
|
||||||
// initialization and is ready to create browser windows.
|
// initialization and is ready to create browser windows.
|
||||||
// Some APIs can only be used after this event occurs.
|
// Some APIs can only be used after this event occurs.
|
||||||
|
@ -1029,23 +1096,6 @@ app.on('ready', async () => {
|
||||||
|
|
||||||
GlobalErrors.updateLocale(locale.messages);
|
GlobalErrors.updateLocale(locale.messages);
|
||||||
|
|
||||||
let key = userConfig.get('key');
|
|
||||||
if (!key) {
|
|
||||||
console.log(
|
|
||||||
'key/initialize: Generating new encryption key, since we did not find it on disk'
|
|
||||||
);
|
|
||||||
// https://www.zetetic.net/sqlcipher/sqlcipher-api/#key
|
|
||||||
key = crypto.randomBytes(32).toString('hex');
|
|
||||||
userConfig.set('key', key);
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlInitTimeStart = Date.now();
|
|
||||||
const sqlInitPromise = sql.initialize({
|
|
||||||
configDir: userDataPath,
|
|
||||||
key,
|
|
||||||
messages: locale.messages,
|
|
||||||
});
|
|
||||||
|
|
||||||
// If the sql initialization takes more than three seconds to complete, we
|
// If the sql initialization takes more than three seconds to complete, we
|
||||||
// want to notify the user that things are happening
|
// want to notify the user that things are happening
|
||||||
const timeout = new Promise(resolve => setTimeout(resolve, 3000, 'timeout'));
|
const timeout = new Promise(resolve => setTimeout(resolve, 3000, 'timeout'));
|
||||||
|
@ -1085,9 +1135,11 @@ app.on('ready', async () => {
|
||||||
loadingWindow.loadURL(prepareURL([__dirname, 'loading.html']));
|
loadingWindow.loadURL(prepareURL([__dirname, 'loading.html']));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Run window preloading in parallel with database initialization.
|
||||||
|
await createWindow();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await sqlInitPromise;
|
await sqlInitPromise;
|
||||||
sqlInitTimeEnd = Date.now();
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('sql.initialize was unsuccessful; returning early');
|
console.log('sql.initialize was unsuccessful; returning early');
|
||||||
const buttonIndex = dialog.showMessageBoxSync({
|
const buttonIndex = dialog.showMessageBoxSync({
|
||||||
|
@ -1182,7 +1234,6 @@ app.on('ready', async () => {
|
||||||
|
|
||||||
ready = true;
|
ready = true;
|
||||||
|
|
||||||
await createWindow();
|
|
||||||
if (usingTrayIcon) {
|
if (usingTrayIcon) {
|
||||||
tray = createTrayIcon(getMainWindow, locale.messages);
|
tray = createTrayIcon(getMainWindow, locale.messages);
|
||||||
}
|
}
|
||||||
|
@ -1451,7 +1502,7 @@ installSettingsGetter('badge-count-muted-conversations');
|
||||||
installSettingsSetter('badge-count-muted-conversations');
|
installSettingsSetter('badge-count-muted-conversations');
|
||||||
|
|
||||||
installSettingsGetter('spell-check');
|
installSettingsGetter('spell-check');
|
||||||
installSettingsSetter('spell-check');
|
installSettingsSetter('spell-check', true);
|
||||||
|
|
||||||
installSettingsGetter('always-relay-calls');
|
installSettingsGetter('always-relay-calls');
|
||||||
installSettingsSetter('always-relay-calls');
|
installSettingsSetter('always-relay-calls');
|
||||||
|
@ -1557,8 +1608,12 @@ function installSettingsGetter(name) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function installSettingsSetter(name) {
|
function installSettingsSetter(name, isEphemeral = false) {
|
||||||
ipc.on(`set-${name}`, (event, value) => {
|
ipc.on(`set-${name}`, (event, value) => {
|
||||||
|
if (isEphemeral) {
|
||||||
|
ephemeralConfig.set('spell-check', value);
|
||||||
|
}
|
||||||
|
|
||||||
if (mainWindow && mainWindow.webContents) {
|
if (mainWindow && mainWindow.webContents) {
|
||||||
ipc.once(`set-success-${name}`, (_event, error) => {
|
ipc.once(`set-success-${name}`, (_event, error) => {
|
||||||
const contents = event.sender;
|
const contents = event.sender;
|
||||||
|
|
|
@ -78,7 +78,8 @@ before(async () => {
|
||||||
await deleteIndexedDB();
|
await deleteIndexedDB();
|
||||||
try {
|
try {
|
||||||
window.log.info('Initializing SQL in renderer');
|
window.log.info('Initializing SQL in renderer');
|
||||||
await window.sqlInitializer.initialize();
|
const isTesting = true;
|
||||||
|
await window.sqlInitializer.initialize(isTesting);
|
||||||
window.log.info('SQL initialized in renderer');
|
window.log.info('SQL initialized in renderer');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
window.log.error(
|
window.log.error(
|
||||||
|
|
|
@ -8,7 +8,18 @@ import sql from './Server';
|
||||||
|
|
||||||
const getRealPath = pify(fs.realpath);
|
const getRealPath = pify(fs.realpath);
|
||||||
|
|
||||||
export async function initialize(): Promise<void> {
|
// Called from renderer.
|
||||||
|
export async function initialize(isTesting = false): Promise<void> {
|
||||||
|
if (!isTesting) {
|
||||||
|
ipc.send('database-ready');
|
||||||
|
|
||||||
|
await new Promise<void>(resolve => {
|
||||||
|
ipc.once('database-ready', () => {
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const configDir = await getRealPath(ipc.sendSync('get-user-data-path'));
|
const configDir = await getRealPath(ipc.sendSync('get-user-data-path'));
|
||||||
const key = ipc.sendSync('user-config-key');
|
const key = ipc.sendSync('user-config-key');
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,10 @@ type PromisePair<T> = {
|
||||||
export class MainSQL {
|
export class MainSQL {
|
||||||
private readonly worker: Worker;
|
private readonly worker: Worker;
|
||||||
|
|
||||||
|
private isReady = false;
|
||||||
|
|
||||||
|
private onReady: Promise<void> | undefined;
|
||||||
|
|
||||||
private readonly onExit: Promise<void>;
|
private readonly onExit: Promise<void>;
|
||||||
|
|
||||||
private seq = 0;
|
private seq = 0;
|
||||||
|
@ -81,16 +85,37 @@ export class MainSQL {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async initialize(options: InitializeOptions): Promise<void> {
|
public async initialize(options: InitializeOptions): Promise<void> {
|
||||||
return this.send({ type: 'init', options });
|
if (this.isReady || this.onReady) {
|
||||||
|
throw new Error('Already initialized');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.onReady = this.send({ type: 'init', options });
|
||||||
|
|
||||||
|
await this.onReady;
|
||||||
|
|
||||||
|
this.onReady = undefined;
|
||||||
|
this.isReady = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async close(): Promise<void> {
|
public async close(): Promise<void> {
|
||||||
|
if (!this.isReady) {
|
||||||
|
throw new Error('Not initialized');
|
||||||
|
}
|
||||||
|
|
||||||
await this.send({ type: 'close' });
|
await this.send({ type: 'close' });
|
||||||
await this.onExit;
|
await this.onExit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
public async sqlCall(method: string, args: ReadonlyArray<any>): Promise<any> {
|
public async sqlCall(method: string, args: ReadonlyArray<any>): Promise<any> {
|
||||||
|
if (this.onReady) {
|
||||||
|
await this.onReady;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.isReady) {
|
||||||
|
throw new Error('Not initialized');
|
||||||
|
}
|
||||||
|
|
||||||
return this.send({ type: 'sqlCall', method, args });
|
return this.send({ type: 'sqlCall', method, args });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue