Skip to content

Commit

Permalink
feat: Error boundary main (#43)
Browse files Browse the repository at this point in the history
* ErrorBoundaryMain

add error boundary for main process

* remove error test

remove error test

* throw an error

throw an error for demonstration purpose

* add IPC error handler

add IPC error handler

* handle fetchedApps undefined

handle fetchedApps  undefined
  • Loading branch information
0xGavinOwen authored Sep 26, 2023
1 parent 66cdbd8 commit 72386c5
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 38 deletions.
85 changes: 54 additions & 31 deletions src/main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,29 @@ import { resolveHtmlPath } from './util';
import { TWEET_INTENT } from './constants';
import { MadaraConfig } from './types';
import FireBaseService from './firebase';
import { IpcMainInvokeEvent } from 'electron';


let mainWindow: BrowserWindow | null = null;

process.on('uncaughtException', (error) => { //Global error handler, to catch error outside IPChandler. Works when electronmon is off
console.error('Unhandled error from main process:', error);

BrowserWindow.getAllWindows().forEach((win) => {
win.webContents.send('backend-error', error);
});
});

function withErrorHandler(handler: (event: IpcMainInvokeEvent, ...args: any[]) => Promise<any>) { //IPC error handler
return async function(event: IpcMainInvokeEvent, ...args: any[]) {
try {
return await handler(event, ...args);
} catch (error) {
console.error("Error in IPC handler:", error);
event.sender.send('backend-error', error);
}
};
}

class AppUpdater {
constructor() {
Expand All @@ -28,29 +51,28 @@ class AppUpdater {
}
}

let mainWindow: BrowserWindow | null = null;

ipcMain.handle('madara-start', async (event, config: MadaraConfig) => {
ipcMain.handle('madara-start', withErrorHandler(async (event, config: MadaraConfig) => {
await Madara.start(mainWindow as BrowserWindow, config);
});
}));

ipcMain.handle('madara-stop', async () => {
ipcMain.handle('madara-stop', withErrorHandler(async () => {
await Madara.stop();
});
}));

ipcMain.handle('madara-delete', async () => {
ipcMain.handle('madara-delete', withErrorHandler(async () => {
await Madara.deleteNode();
});
}));

ipcMain.handle('madara-setup', async (event, config: MadaraConfig) => {
ipcMain.handle('madara-setup', withErrorHandler(async (event, config: MadaraConfig) => {
await Madara.setup(mainWindow as BrowserWindow, config);
});
}));

ipcMain.handle('release-exists', async (event, config: MadaraConfig) => {
ipcMain.handle('release-exists', withErrorHandler(async (event, config: MadaraConfig) => {
return Madara.releaseExists(config);
});
}));

ipcMain.handle('send-tweet', async () => {
ipcMain.handle('send-tweet', withErrorHandler(async () => {
await Madara.getCurrentWindowScreenshot(mainWindow as BrowserWindow);

const file = await Madara.fetchScreenshotFromSystem();
Expand All @@ -66,42 +88,43 @@ ipcMain.handle('send-tweet', async () => {

// open link in browser
shell.openExternal(TWEET_INTENT + shortenedLink);
});
}));

ipcMain.handle('child-process-in-memory', (): boolean => {
ipcMain.handle('child-process-in-memory', withErrorHandler(async (): Promise<boolean> => {
return Madara.childProcessInMemory();
});
}));

ipcMain.handle('madara-app-download', async (event, appId: string) => {
ipcMain.handle('madara-app-download', withErrorHandler(async (event, appId: string) => {
await MadaraApp.downloadApp(mainWindow as BrowserWindow, appId);
});
}));

ipcMain.handle('madara-installed-apps', () => {
return MadaraApp.getInstalledApps();
});
ipcMain.handle('madara-installed-apps', withErrorHandler(async () => {
return Promise.resolve(MadaraApp.getInstalledApps());
}));

ipcMain.handle('madara-app-start', (event, appId: string) => {
return MadaraApp.startApp(mainWindow as BrowserWindow, appId);
});
ipcMain.handle('madara-app-start', withErrorHandler(async (event, appId: string) => {
return await MadaraApp.startApp(mainWindow as BrowserWindow, appId);
}));

ipcMain.handle('madara-app-stop', (event, appId: string) => {
ipcMain.handle('madara-app-stop', withErrorHandler(async (event, appId: string) => {
return MadaraApp.stopApp(mainWindow as BrowserWindow, appId);
});
}));

ipcMain.handle(
'madara-app-update-settings',
(event, appId: string, settings: any) => {
withErrorHandler(async (event, appId: string, settings: any) => {
return MadaraApp.updateAppSettings(appId, settings);
}
})
);

ipcMain.handle('madara-app-get-settings', (event, appId: string) => {
ipcMain.handle('madara-app-get-settings', withErrorHandler(async (event, appId: string) => {
return MadaraApp.getAppSettings(appId);
});
}));

ipcMain.handle('madara-fetch-all-running-apps', () => {
ipcMain.handle('madara-fetch-all-running-apps', withErrorHandler(async () => {
return MadaraApp.fetchAllRunningApps(mainWindow as BrowserWindow);
});
}));


if (process.env.NODE_ENV === 'production') {
const sourceMapSupport = require('source-map-support');
Expand Down
6 changes: 6 additions & 0 deletions src/main/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ const electronHandler = {
fetchAllRunningApps: () =>
ipcRenderer.invoke('madara-fetch-all-running-apps'),
},
onUnhandledError: (callback: (message: string) => void) =>
ipcRenderer.on('backend-error', (event, message) => callback(message)),
offUnhandledError: (callback: (message: string) => void) =>
ipcRenderer.removeListener('backend-error', (event, message) =>
callback(message)
),
},
};

Expand Down
20 changes: 13 additions & 7 deletions src/renderer/features/appsSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,21 @@ export const updateAppRunningStatus =
};

export const fetchAndSetRunningApps = () => async (dispatch: any) => {
const fetchedApps =
await window.electron.ipcRenderer.madaraApp.fetchAllRunningApps();
const appsObject = fetchedApps.reduce((acc: any, app: any) => {
acc[app.id] = true;
return acc;
}, {});
dispatch(setRunningApps(appsObject));
const fetchedApps = await window.electron.ipcRenderer.madaraApp.fetchAllRunningApps();

// Check if fetchedApps is defined and it's an array.
if (Array.isArray(fetchedApps)) {
const appsObject = fetchedApps.reduce((acc: any, app: any) => {
acc[app.id] = true;
return acc;
}, {});
dispatch(setRunningApps(appsObject));
} else {
console.error('Failed to fetch running apps:', fetchedApps);
}
};


export const setupInstalledApps = () => async (dispatch: any) => {
const installedApps =
await window.electron.ipcRenderer.madaraApp.installedApps();
Expand Down
31 changes: 31 additions & 0 deletions src/renderer/hooks/useErrorBoundaryMain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useEffect } from 'react';
import { showSnackbar } from 'renderer/store/snackbar';
import { useAppDispatch } from 'renderer/utils/hooks';

// Global variable to check if the listener has already been attached
let hasListenerBeenAttached = false;

function useErrorBoundaryMain() {
const dispatch = useAppDispatch();

useEffect(() => {
if (hasListenerBeenAttached) {
// If the listener is already attached, no need to attach it again
return;
}

function handleUnhandledError(message: any) {
console.error('Unhandled error from main process:', message);
dispatch(showSnackbar('Something went wrong'));
}

window.electron.ipcRenderer.onUnhandledError(handleUnhandledError);
hasListenerBeenAttached = true;

return () => { //clean mount
window.electron.ipcRenderer.offUnhandledError(handleUnhandledError);
};
}, [dispatch]);
}

export default useErrorBoundaryMain;
3 changes: 3 additions & 0 deletions src/renderer/pages/Landing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import Button from '../components/Button';
import InfiniteBarLoader from '../components/InfiniteBarLoader';
import Input from '../components/Input';
import SharinganEye from '../components/SharinganEye';
import useErrorBoundaryMain from 'renderer/hooks/useErrorBoundaryMain';

const LandingContainer = styled(motion.div)`
background-color: black;
Expand Down Expand Up @@ -190,6 +191,8 @@ export default function Landing() {
);
};

useErrorBoundaryMain();

return (
<LandingContainer
initial={{ opacity: 1 }}
Expand Down

0 comments on commit 72386c5

Please sign in to comment.