From b7548126d094afd8b32e17fb98c2bbee3cb4cbc0 Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 8 Feb 2022 10:23:29 -0700 Subject: [PATCH 1/2] Error catch recent sessions parsing --- products/jbrowse-desktop/public/electron.ts | 65 +++++++++------------ 1 file changed, 26 insertions(+), 39 deletions(-) diff --git a/products/jbrowse-desktop/public/electron.ts b/products/jbrowse-desktop/public/electron.ts index 866074b40a..5083dcee27 100644 --- a/products/jbrowse-desktop/public/electron.ts +++ b/products/jbrowse-desktop/public/electron.ts @@ -15,10 +15,29 @@ const { unlink, readFile, copyFile, readdir, writeFile } = fs.promises const { app, ipcMain, shell, BrowserWindow, Menu } = electron +interface Session { + path: string + updated: number + name: string +} + function stringify(obj: unknown) { return JSON.stringify(obj, null, 2) } +async function readSessions(): Promise { + let data: string + try { + data = await readFile(recentSessionsPath, 'utf8') + return JSON.parse(data) + } catch (e) { + console.error( + `Failed to parse existing recentSessionsPath, data was ${data}`, + ) + return e + } +} + // manual auto-updates https://github.com/electron-userland/electron-builder/blob/docs/encapsulated%20manual%20update%20via%20menu.js autoUpdater.autoDownload = false @@ -424,9 +443,7 @@ ipcMain.handle( ipcMain.handle( 'createInitialAutosaveFile', async (_event: unknown, snap: SessionSnap) => { - const rows = JSON.parse(fs.readFileSync(recentSessionsPath, 'utf8')) as [ - { path: string; updated: number }, - ] + const rows = await readSessions() const idx = rows.findIndex(r => r.path === path) const path = getAutosavePath(`${+Date.now()}`) const entry = { @@ -452,10 +469,10 @@ ipcMain.handle( ipcMain.handle( 'saveSession', async (_event: unknown, path: string, snap: SessionSnap) => { - const page = await mainWindow?.capturePage() - const rows = JSON.parse(fs.readFileSync(recentSessionsPath, 'utf8')) as [ - { path: string; updated: number }, - ] + const [page, rows] = await Promise.all([ + mainWindow?.capturePage(), + readSessions(), + ]) const idx = rows.findIndex(r => r.path === path) const png = page?.resize({ width: 500 }).toDataURL() const entry = { @@ -508,11 +525,7 @@ ipcMain.handle('promptSessionSaveAs', async (_event: unknown) => { ipcMain.handle( 'deleteSessions', async (_event: unknown, sessionPaths: string[]) => { - const sessions = JSON.parse(await readFile(recentSessionsPath, 'utf8')) as { - path: string - name: string - }[] - + const sessions = await readSessions() const indexes: number[] = [] sessions.forEach((row, idx) => { if (sessionPaths.includes(row.path)) { @@ -535,36 +548,10 @@ ipcMain.handle( }, ) -ipcMain.handle( - 'deleteSession', - async (_event: unknown, sessionPath: string) => { - const sessions = JSON.parse(await readFile(recentSessionsPath, 'utf8')) as { - path: string - name: string - }[] - - const idx = sessions.findIndex(row => row.path === sessionPath) - if (idx !== -1) { - sessions.splice(idx, 1) - } else { - throw new Error(`Session at ${path} not found`) - } - - await Promise.all([ - writeFile(recentSessionsPath, stringify(sessions)), - unlink(getThumbnailPath(sessionPath)).catch(e => console.error(e)), - unlink(sessionPath).catch(e => console.error(e)), - ]) - }, -) - ipcMain.handle( 'renameSession', async (_event: unknown, path: string, newName: string) => { - const sessions = JSON.parse(await readFile(recentSessionsPath, 'utf8')) as { - path: string - name: string - }[] + const sessions = await readSessions() const session = JSON.parse(await readFile(path, 'utf8')) const idx = sessions.findIndex(row => row.path === path) if (idx !== -1) { From 1d20a566bcf10badef83f9b31f46e5a1502d9009 Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 8 Feb 2022 10:32:16 -0700 Subject: [PATCH 2/2] Small further refactoring --- products/jbrowse-desktop/public/electron.ts | 69 ++++++++++++++------- 1 file changed, 48 insertions(+), 21 deletions(-) diff --git a/products/jbrowse-desktop/public/electron.ts b/products/jbrowse-desktop/public/electron.ts index 5083dcee27..639bda0ffd 100644 --- a/products/jbrowse-desktop/public/electron.ts +++ b/products/jbrowse-desktop/public/electron.ts @@ -15,7 +15,7 @@ const { unlink, readFile, copyFile, readdir, writeFile } = fs.promises const { app, ipcMain, shell, BrowserWindow, Menu } = electron -interface Session { +interface RecentSession { path: string updated: number name: string @@ -25,16 +25,47 @@ function stringify(obj: unknown) { return JSON.stringify(obj, null, 2) } -async function readSessions(): Promise { - let data: string +async function readRecentSessions(): Promise { + let data = '' try { data = await readFile(recentSessionsPath, 'utf8') return JSON.parse(data) } catch (e) { console.error( `Failed to parse existing recentSessionsPath, data was ${data}`, + e, ) - return e + return [] + } +} + +async function readSession( + sessionPath: string, +): Promise<{ assemblies?: unknown[] }> { + let data = '' + try { + data = await readFile(sessionPath, 'utf8') + return JSON.parse(data) + } catch (e) { + console.error( + `Failed to parse session at "${sessionPath}", data was ${data}`, + e, + ) + return {} + } +} + +async function readQuickstart(quickstartPath: string): Promise { + let data = '' + try { + data = await readFile(quickstartPath, 'utf8') + return JSON.parse(data) + } catch (e) { + console.error( + `Failed to parse quickstart at "${quickstartPath}", data was ${data}`, + e, + ) + return {} } } @@ -351,9 +382,7 @@ ipcMain.handle( ipcMain.handle( 'listSessions', async (_event: unknown, showAutosaves: boolean) => { - const sessions = JSON.parse(await readFile(recentSessionsPath, 'utf8')) as { - path: string - }[] + const sessions = await readRecentSessions() if (!showAutosaves) { return sessions.filter(f => !f.path.startsWith(autosaveDir)) @@ -368,7 +397,7 @@ ipcMain.handle('loadExternalConfig', (_event: unknown, sessionPath) => { }) ipcMain.handle('loadSession', async (_event: unknown, sessionPath: string) => { - const sessionSnapshot = JSON.parse(await readFile(sessionPath, 'utf8')) + const sessionSnapshot = await readSession(sessionPath) if (!sessionSnapshot.assemblies) { throw new Error( `File at ${sessionPath} does not appear to be a JBrowse session. It does not contain any assemblies.`, @@ -407,7 +436,7 @@ ipcMain.handle( ) ipcMain.handle('getQuickstart', async (_event: unknown, name: string) => { - return JSON.parse(await readFile(getQuickstartPath(name), 'utf8')) + return readQuickstart(getQuickstartPath(name)) }) ipcMain.handle( @@ -443,7 +472,7 @@ ipcMain.handle( ipcMain.handle( 'createInitialAutosaveFile', async (_event: unknown, snap: SessionSnap) => { - const rows = await readSessions() + const rows = await readRecentSessions() const idx = rows.findIndex(r => r.path === path) const path = getAutosavePath(`${+Date.now()}`) const entry = { @@ -471,7 +500,7 @@ ipcMain.handle( async (_event: unknown, path: string, snap: SessionSnap) => { const [page, rows] = await Promise.all([ mainWindow?.capturePage(), - readSessions(), + readRecentSessions(), ]) const idx = rows.findIndex(r => r.path === path) const png = page?.resize({ width: 500 }).toDataURL() @@ -525,15 +554,13 @@ ipcMain.handle('promptSessionSaveAs', async (_event: unknown) => { ipcMain.handle( 'deleteSessions', async (_event: unknown, sessionPaths: string[]) => { - const sessions = await readSessions() - const indexes: number[] = [] - sessions.forEach((row, idx) => { - if (sessionPaths.includes(row.path)) { - indexes.push(idx) - } - }) - for (let i = indexes.length - 1; i >= 0; i--) { - sessions.splice(indexes[i], 1) + const sessions = await readRecentSessions() + const indices = sessions + .map((r, i) => (sessionPaths.includes(r.path) ? i : undefined)) + .filter((f): f is number => f !== undefined) + + for (let i = indices.length - 1; i >= 0; i--) { + sessions.splice(indices[i], 1) } await Promise.all([ @@ -551,7 +578,7 @@ ipcMain.handle( ipcMain.handle( 'renameSession', async (_event: unknown, path: string, newName: string) => { - const sessions = await readSessions() + const sessions = await readRecentSessions() const session = JSON.parse(await readFile(path, 'utf8')) const idx = sessions.findIndex(row => row.path === path) if (idx !== -1) {