Skip to content

Commit

Permalink
Merge pull request #464 from 18alantom/fix-dbfile-issues
Browse files Browse the repository at this point in the history
fix: db file related issues
  • Loading branch information
18alantom authored Aug 31, 2022
2 parents 65a91e6 + ef26c18 commit 2351b90
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 41 deletions.
62 changes: 42 additions & 20 deletions backend/database/manager.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { constants } from 'fs';
import fs from 'fs/promises';
import path from 'path';
import { DatabaseDemuxBase, DatabaseMethod } from 'utils/db/types';
import { getSchemas } from '../../schemas';
import { databaseMethodSet } from '../helpers';
import {
databaseMethodSet,
emitMainProcessError,
unlinkIfExists,
} from '../helpers';
import patches from '../patches';
import { BespokeQueries } from './bespoke';
import DatabaseCore from './core';
Expand All @@ -22,7 +25,7 @@ export class DatabaseManager extends DatabaseDemuxBase {
}

async createNewDatabase(dbPath: string, countryCode: string) {
await this.#unlinkIfExists(dbPath);
await unlinkIfExists(dbPath);
return await this.connectToDatabase(dbPath, countryCode);
}

Expand Down Expand Up @@ -61,12 +64,35 @@ export class DatabaseManager extends DatabaseDemuxBase {
try {
await this.#runPatchesAndMigrate();
} catch (err) {
console.error(err);
await this.db!.close();
copyPath && (await fs.copyFile(copyPath, dbPath));
throw err;
this.#handleFailedMigration(err, dbPath, copyPath);
} finally {
copyPath && (await fs.unlink(copyPath));
await unlinkIfExists(copyPath);
}
}

async #handleFailedMigration(
error: unknown,
dbPath: string,
copyPath: string | null
) {
await this.db!.close();

if (copyPath) {
await this.#restoreDbCopy(dbPath, copyPath);
}

if (error instanceof Error) {
error.message = `failed migration\n${error.message}`;
}

throw error;
}

async #restoreDbCopy(dbPath: string, copyPath: string) {
try {
await fs.copyFile(copyPath!, dbPath);
} catch (err) {
emitMainProcessError(err);
}
}

Expand Down Expand Up @@ -130,17 +156,6 @@ export class DatabaseManager extends DatabaseDemuxBase {
return await queryFunction(this.db!, ...args);
}

async #unlinkIfExists(dbPath: string) {
const exists = await fs
.access(dbPath, constants.W_OK)
.then(() => true)
.catch(() => false);

if (exists) {
fs.unlink(dbPath);
}
}

async #getIsFirstRun(): Promise<boolean> {
if (!this.#isInitialized) {
return true;
Expand All @@ -160,7 +175,14 @@ export class DatabaseManager extends DatabaseDemuxBase {

const dir = path.parse(src).dir;
const dest = path.join(dir, '__premigratory_temp.db');
await fs.copyFile(src, dest);

try {
await fs.copyFile(src, dest);
} catch (err) {
emitMainProcessError(err);
return null;
}

return dest;
}
}
Expand Down
32 changes: 32 additions & 0 deletions backend/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { constants } from 'fs';
import fs from 'fs/promises';
import { DatabaseMethod } from 'utils/db/types';
import { CUSTOM_EVENTS } from 'utils/messages';
import { KnexColumnType } from './database/types';

export const sqliteTypeMap: Record<string, KnexColumnType> = {
Expand Down Expand Up @@ -47,3 +50,32 @@ export const databaseMethodSet: Set<DatabaseMethod> = new Set([
'close',
'exists',
]);

export function emitMainProcessError(
error: unknown,
more?: Record<string, unknown>
) {
(process.emit as Function)(CUSTOM_EVENTS.MAIN_PROCESS_ERROR, error, more);
}

export async function checkFileAccess(filePath: string, mode?: number) {
mode ??= constants.W_OK;
return await fs
.access(filePath, mode)
.then(() => true)
.catch(() => false);
}

export async function unlinkIfExists(filePath: unknown) {
if (!filePath || typeof filePath !== 'string') {
return false;
}

const exists = await checkFileAccess(filePath);
if (exists) {
await fs.unlink(filePath);
return true;
}

return false;
}
14 changes: 14 additions & 0 deletions main/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,17 @@ export async function getErrorHandledReponse(func: () => Promise<unknown>) {
export function rendererLog(main: Main, ...args: unknown[]) {
main.mainWindow?.webContents.send(IPC_CHANNELS.CONSOLE_LOG, ...args);
}

export function isNetworkError(error: Error) {
switch (error?.message) {
case 'net::ERR_INTERNET_DISCONNECTED':
case 'net::ERR_PROXY_CONNECTION_FAILED':
case 'net::ERR_CONNECTION_RESET':
case 'net::ERR_CONNECTION_CLOSE':
case 'net::ERR_NAME_NOT_RESOLVED':
case 'net::ERR_CONNECTION_TIMED_OUT':
return true;
default:
return false;
}
}
30 changes: 23 additions & 7 deletions main/registerAutoUpdaterListeners.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import { emitMainProcessError } from 'backend/helpers';
import { app, dialog } from 'electron';
import { autoUpdater, UpdateInfo } from 'electron-updater';
import { Main } from '../main';
import { IPC_CHANNELS } from '../utils/messages';
import { isNetworkError } from './helpers';

export default function registerAutoUpdaterListeners(main: Main) {
autoUpdater.autoDownload = false;
autoUpdater.allowPrerelease = true;
autoUpdater.autoInstallOnAppQuit = true;

autoUpdater.on('error', (error) => {
if (!main.checkedForUpdate) {
main.checkedForUpdate = true;
}

if (isNetworkError(error)) {
return;
}

main.mainWindow!.webContents.send(IPC_CHANNELS.MAIN_PROCESS_ERROR, error);
dialog.showErrorBox(
'Update Error: ',
error == null ? 'unknown' : (error.stack || error).toString()
);
emitMainProcessError(error);
});

autoUpdater.on('update-available', async (info: UpdateInfo) => {
Expand All @@ -30,7 +31,7 @@ export default function registerAutoUpdaterListeners(main: Main) {
if (!isCurrentBeta && isNextBeta) {
const option = await dialog.showMessageBox({
type: 'info',
title: `Update Frappe Books?`,
title: 'Update Available',
message: `Download version ${nextVersion}?`,
buttons: ['Yes', 'No'],
});
Expand All @@ -44,4 +45,19 @@ export default function registerAutoUpdaterListeners(main: Main) {

await autoUpdater.downloadUpdate();
});

autoUpdater.on('update-downloaded', async () => {
const option = await dialog.showMessageBox({
type: 'info',
title: 'Update Downloaded',
message: 'Restart Frappe Books to install update?',
buttons: ['Yes', 'No'],
});

if (option.response === 1) {
return;
}

autoUpdater.quitAndInstall();
});
}
18 changes: 15 additions & 3 deletions main/registerIpcMainActionListeners.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { emitMainProcessError } from 'backend/helpers';
import { app, dialog, ipcMain } from 'electron';
import { autoUpdater } from 'electron-updater';
import fs from 'fs/promises';
Expand All @@ -11,7 +12,8 @@ import { getLanguageMap } from './getLanguageMap';
import {
getConfigFilesWithModified,
getErrorHandledReponse,
setAndGetCleanedConfigFiles,
isNetworkError,
setAndGetCleanedConfigFiles
} from './helpers';
import { saveHtmlAsPdf } from './saveHtmlAsPdf';

Expand Down Expand Up @@ -52,10 +54,20 @@ export default function registerIpcMainActionListeners(main: Main) {
});

ipcMain.handle(IPC_ACTIONS.CHECK_FOR_UPDATES, async () => {
if (!main.isDevelopment && !main.checkedForUpdate) {
if (main.isDevelopment || main.checkedForUpdate) {
return;
}

try {
await autoUpdater.checkForUpdates();
main.checkedForUpdate = true;
} catch (error) {
if (isNetworkError(error as Error)) {
return;
}

emitMainProcessError(error);
}
main.checkedForUpdate = true;
});

ipcMain.handle(IPC_ACTIONS.GET_LANGUAGE_MAP, async (event, code) => {
Expand Down
20 changes: 17 additions & 3 deletions main/registerProcessListeners.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { app } from 'electron';
import { IPC_CHANNELS } from 'utils/messages';
import { CUSTOM_EVENTS, IPC_CHANNELS } from 'utils/messages';
import { Main } from '../main';

export default function registerProcessListeners(main: Main) {
Expand All @@ -17,12 +17,26 @@ export default function registerProcessListeners(main: Main) {
}
}

process.on(CUSTOM_EVENTS.MAIN_PROCESS_ERROR, (error, more) => {
main.mainWindow!.webContents.send(
IPC_CHANNELS.LOG_MAIN_PROCESS_ERROR,
error,
more
);
});

process.on('unhandledRejection', (error) => {
main.mainWindow!.webContents.send(IPC_CHANNELS.MAIN_PROCESS_ERROR, error);
main.mainWindow!.webContents.send(
IPC_CHANNELS.LOG_MAIN_PROCESS_ERROR,
error
);
});

process.on('uncaughtException', (error) => {
main.mainWindow!.webContents.send(IPC_CHANNELS.MAIN_PROCESS_ERROR, error);
main.mainWindow!.webContents.send(
IPC_CHANNELS.LOG_MAIN_PROCESS_ERROR,
error
);
setTimeout(() => process.exit(1), 10000);
});
}
6 changes: 5 additions & 1 deletion src/errorHandling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,11 @@ export function getErrorLogObject(
error: Error,
more: Record<string, unknown>
): ErrorLog {
const { name, stack, message } = error;
const { name, stack, message, cause } = error;
if (cause) {
more.cause = cause;
}

const errorLogObj = { name, stack, message, more };

fyo.errorLog.push(errorLogObj);
Expand Down
15 changes: 9 additions & 6 deletions src/renderer/registerIpcRendererListeners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ import { fyo } from 'src/initFyo';
import { IPC_CHANNELS } from 'utils/messages';

export default function registerIpcRendererListeners() {
ipcRenderer.on(IPC_CHANNELS.MAIN_PROCESS_ERROR, async (_, error) => {
if (fyo.store.isDevelopment) {
console.error(error);
}
ipcRenderer.on(
IPC_CHANNELS.LOG_MAIN_PROCESS_ERROR,
async (_, error, more) => {
if (fyo.store.isDevelopment) {
console.error(error);
}

await handleError(true, error as Error);
});
await handleError(true, error as Error, more);
}
);

ipcRenderer.on(IPC_CHANNELS.CONSOLE_LOG, (_, ...stuff: unknown[]) => {
if (!fyo.store.isDevelopment) {
Expand Down
7 changes: 6 additions & 1 deletion utils/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export enum IPC_ACTIONS {

// ipcMain.send(...)
export enum IPC_CHANNELS {
MAIN_PROCESS_ERROR = 'main-process-error',
LOG_MAIN_PROCESS_ERROR = 'main-process-error',
CONSOLE_LOG = 'console-log',
}

Expand All @@ -42,3 +42,8 @@ export enum DB_CONN_FAILURE {
CANT_OPEN = 'cant-open',
CANT_CONNECT = 'cant-connect',
}

// events
export enum CUSTOM_EVENTS {
MAIN_PROCESS_ERROR = 'main-process-error',
}

0 comments on commit 2351b90

Please sign in to comment.