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 () => {
 | 
			
		||||
  try {
 | 
			
		||||
    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');
 | 
			
		||||
  } catch (err) {
 | 
			
		||||
    window.log.error(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										107
									
								
								main.js
									
										
									
									
									
								
							
							
						
						
									
										107
									
								
								main.js
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -133,14 +133,22 @@ const defaultWebPrefs = {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
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']);
 | 
			
		||||
 | 
			
		||||
  // Default to `true` if setting doesn't exist yet
 | 
			
		||||
  if (!json) {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  const slowValue = json ? json.value : true;
 | 
			
		||||
 | 
			
		||||
  return json.value;
 | 
			
		||||
  ephemeralConfig.set('spell-check', slowValue);
 | 
			
		||||
 | 
			
		||||
  console.log('got slow spellcheck setting', slowValue);
 | 
			
		||||
 | 
			
		||||
  return slowValue;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function showWindow() {
 | 
			
		||||
| 
						 | 
				
			
			@ -316,7 +324,7 @@ if (OS.isWindows()) {
 | 
			
		|||
async function createWindow() {
 | 
			
		||||
  const { screen } = electron;
 | 
			
		||||
  const windowOptions = {
 | 
			
		||||
    show: !startInTray, // allow to start minimised in tray
 | 
			
		||||
    show: false,
 | 
			
		||||
    width: DEFAULT_WIDTH,
 | 
			
		||||
    height: DEFAULT_HEIGHT,
 | 
			
		||||
    minWidth: MIN_WIDTH,
 | 
			
		||||
| 
						 | 
				
			
			@ -528,8 +536,44 @@ async function createWindow() {
 | 
			
		|||
  mainWindow.on('leave-full-screen', () => {
 | 
			
		||||
    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', () => {
 | 
			
		||||
  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
 | 
			
		||||
// initialization and is ready to create browser windows.
 | 
			
		||||
// Some APIs can only be used after this event occurs.
 | 
			
		||||
| 
						 | 
				
			
			@ -1029,23 +1096,6 @@ app.on('ready', async () => {
 | 
			
		|||
 | 
			
		||||
  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
 | 
			
		||||
  // want to notify the user that things are happening
 | 
			
		||||
  const timeout = new Promise(resolve => setTimeout(resolve, 3000, 'timeout'));
 | 
			
		||||
| 
						 | 
				
			
			@ -1085,9 +1135,11 @@ app.on('ready', async () => {
 | 
			
		|||
    loadingWindow.loadURL(prepareURL([__dirname, 'loading.html']));
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // Run window preloading in parallel with database initialization.
 | 
			
		||||
  await createWindow();
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    await sqlInitPromise;
 | 
			
		||||
    sqlInitTimeEnd = Date.now();
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.log('sql.initialize was unsuccessful; returning early');
 | 
			
		||||
    const buttonIndex = dialog.showMessageBoxSync({
 | 
			
		||||
| 
						 | 
				
			
			@ -1182,7 +1234,6 @@ app.on('ready', async () => {
 | 
			
		|||
 | 
			
		||||
  ready = true;
 | 
			
		||||
 | 
			
		||||
  await createWindow();
 | 
			
		||||
  if (usingTrayIcon) {
 | 
			
		||||
    tray = createTrayIcon(getMainWindow, locale.messages);
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -1451,7 +1502,7 @@ installSettingsGetter('badge-count-muted-conversations');
 | 
			
		|||
installSettingsSetter('badge-count-muted-conversations');
 | 
			
		||||
 | 
			
		||||
installSettingsGetter('spell-check');
 | 
			
		||||
installSettingsSetter('spell-check');
 | 
			
		||||
installSettingsSetter('spell-check', true);
 | 
			
		||||
 | 
			
		||||
installSettingsGetter('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) => {
 | 
			
		||||
    if (isEphemeral) {
 | 
			
		||||
      ephemeralConfig.set('spell-check', value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (mainWindow && mainWindow.webContents) {
 | 
			
		||||
      ipc.once(`set-success-${name}`, (_event, error) => {
 | 
			
		||||
        const contents = event.sender;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -78,7 +78,8 @@ before(async () => {
 | 
			
		|||
  await deleteIndexedDB();
 | 
			
		||||
  try {
 | 
			
		||||
    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');
 | 
			
		||||
  } catch (err) {
 | 
			
		||||
    window.log.error(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,18 @@ import sql from './Server';
 | 
			
		|||
 | 
			
		||||
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 key = ipc.sendSync('user-config-key');
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -44,6 +44,10 @@ type PromisePair<T> = {
 | 
			
		|||
export class MainSQL {
 | 
			
		||||
  private readonly worker: Worker;
 | 
			
		||||
 | 
			
		||||
  private isReady = false;
 | 
			
		||||
 | 
			
		||||
  private onReady: Promise<void> | undefined;
 | 
			
		||||
 | 
			
		||||
  private readonly onExit: Promise<void>;
 | 
			
		||||
 | 
			
		||||
  private seq = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -81,16 +85,37 @@ export class MainSQL {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  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> {
 | 
			
		||||
    if (!this.isReady) {
 | 
			
		||||
      throw new Error('Not initialized');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    await this.send({ type: 'close' });
 | 
			
		||||
    await this.onExit;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // eslint-disable-next-line @typescript-eslint/no-explicit-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 });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue