Skip to content

Commit 6439d67

Browse files
🛠️ refactor: improve file handling and error management in main.ts
Refined the file handling in `main.ts` by introducing a `getFile` function. This function first checks if the file exists before attempting to read it, reducing the risk of unhandled exceptions and ensuring smoother file operations. Additionally, it incorporates improved error logging and reporting to Sentry, enhancing the application's ability to diagnose and track issues. These changes aim to make the application more robust and reliable, particularly in scenarios involving file reads and writes, and to provide more detailed diagnostic information in case of errors.
1 parent cadd849 commit 6439d67

1 file changed

Lines changed: 68 additions & 42 deletions

File tree

electron/main.ts

Lines changed: 68 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,35 @@ Sentry.init({
2323
dsn: 'https://d9c49d59e5554239ac977e3a7c409cda@glitchtip.dermot.email/2'
2424
});
2525

26+
const getFile = async (filePath: string, defaultValue: any): Promise<any> => {
27+
try {
28+
// Check if the file exists before reading
29+
if (!existsSync(filePath)) {
30+
console.log(`File does not exist: ${filePath}`);
31+
return defaultValue;
32+
}
33+
34+
const data = await readFilePromise(filePath, 'utf-8');
35+
// If defaultValue is {} or [], try to JSON parse, otherwise don't
36+
let parsed = (defaultValue instanceof Array || defaultValue instanceof Object) ? JSON.parse(data) : data;
37+
return parsed;
38+
} catch (error: any) {
39+
console.log(error)
40+
Sentry.captureException(new Error(`Failed to read file: ${filePath} with default value: ${defaultValue}. Error: ${error?.message}`), {
41+
tags: { module: "readFile" },
42+
extra: { error, filePath, defaultValue }
43+
});
44+
return defaultValue;
45+
}
46+
};
47+
2648
const getPreferences = async (): Promise<Preference[] | null> => {
2749
try {
28-
const preferences = await readFilePromise(userPreferencesFilePath, 'utf-8');
29-
let parsed = JSON.parse(preferences) as Preference[] ?? [];
30-
if (!Array.isArray(parsed)) return [];
50+
const preferences = await getFile(userPreferencesFilePath, []) as Preference[]
51+
if (!Array.isArray(preferences)) return [];
3152

3253
// Remove duplicates based on Preference.name
33-
const uniquePreferences = Array.from(new Map(parsed.map(preference => [preference.name, preference])).values());
54+
const uniquePreferences = Array.from(new Map(preferences.map(preference => [preference.name, preference])).values());
3455
return uniquePreferences;
3556
} catch (error: any) {
3657
console.log(error)
@@ -67,6 +88,7 @@ getPreference('errorLoggingEnabled').then((errorLoggingEnabled: string | boolean
6788
logger.info('App starting...');
6889

6990
import ffmpeg from 'fluent-ffmpeg';
91+
import { existsSync } from 'fs';
7092
const ffmpegPath = require('ffmpeg-static').replace(
7193
'app.asar',
7294
'app.asar.unpacked'
@@ -131,7 +153,7 @@ ipcMain.handle('get-desktop-capturer-sources', async () => {
131153
if (!sourceMatched) return;
132154
const sourceThumbnail = sourceMatched?.thumbnail.toDataURL() ?? '';
133155
const sourceId = sourceMatched?.id ?? '';
134-
if (!sourceThumbnail || !sourceId || !window.ownerName || window.ownerName === 'ScreenLink') return;
156+
if (!sourceThumbnail || !sourceId || !window.ownerName || window.ownerName === 'ScreenLink' || window.ownerName === 'Electron') return;
135157

136158
return {
137159
id: sourceId,
@@ -217,7 +239,7 @@ ipcMain.handle('start-recording', async (_, applicationName?: string) => {
217239
ipcMain.handle('stop-recording', async (_) => {
218240
if (floatingWindow) floatingWindow.hide();
219241
if (webcamWindow) {
220-
toggleCameraWindow(true);
242+
toggleCameraWindow(false);
221243
webcamWindow.setAlwaysOnTop(false);
222244
webcamWindow.minimize();
223245
webcamWindow.hide();
@@ -375,7 +397,6 @@ ipcMain.handle('get-upload-link', async (_, sourceTitle: string): Promise<Upload
375397
console.log(error)
376398
Sentry.captureException(new Error(`Failed to get upload link: ${error?.message}`), {
377399
tags: { module: "getUploadLink" },
378-
extra: { error }
379400
});
380401
throw new Error(JSON.stringify({ e: "failed to get upload link", error }))
381402
}
@@ -496,7 +517,7 @@ const getDeviceCode = async () => {
496517
try {
497518
// Read the device code from the file (deviceCodeFilePath)
498519
// and send it to the renderer process
499-
const deviceCodeBuffer = await readFilePromise(deviceCodeFilePath);
520+
const deviceCodeBuffer = await getFile(deviceCodeFilePath, '');
500521
const deviceCode = deviceCodeBuffer.toString();
501522

502523
if (!deviceCode) {
@@ -528,8 +549,8 @@ const getAccount = async (): Promise<Account | null> => {
528549
}
529550

530551
// Auth cache stored for 5 minutes
531-
const userAccountFileBuffer = await readFilePromise(userAccountFilePath);
532-
const userAccount: Account = JSON.parse(userAccountFileBuffer.toString());
552+
const userAccount = await getFile(userAccountFilePath, {});
553+
533554
// Check if the user account was updated less than 5 minutes ago
534555
const currentTime = new Date().getTime();
535556
const lastUpdatedTime = new Date(userAccount.lastUpdated).getTime();
@@ -538,7 +559,6 @@ const getAccount = async (): Promise<Account | null> => {
538559
return userAccount;
539560
}
540561

541-
542562
// Verify the device code
543563
const device: Account = await verifyDeviceCode(deviceCode);
544564
if (!device) {
@@ -652,9 +672,11 @@ ipcMain.handle('get-device-code', async (_) => {
652672

653673
ipcMain.handle('logout', async (_) => {
654674
try {
655-
// Clear the user account and device code
675+
// Clear the user account, device code and preferences
656676
await writeFilePromise(userAccountFilePath, JSON.stringify({}));
657-
await writeFilePromise(deviceCodeFilePath, JSON.stringify({}));
677+
await writeFilePromise(deviceCodeFilePath, '');
678+
await writeFilePromise(userPreferencesFilePath, JSON.stringify([]));
679+
658680
// Send a logout event to the renderer process
659681
if (mainWindow) mainWindow.webContents.send('device-code', '');
660682
if (floatingWindow) floatingWindow.hide();
@@ -712,12 +734,10 @@ const missingPermissions = async () => {
712734
return missingList;
713735
}
714736

715-
setTimeout(() => {
716-
Sentry.captureException(new Error(`Testing sentry`));
717-
});
718-
719737
const requestPermissions = async (permission: string): Promise<boolean> => {
720738
try {
739+
if (webcamWindow) webcamWindow.hide();
740+
721741
if (permission === 'camera' || permission === 'microphone') {
722742
const status = await systemPreferences.askForMediaAccess(permission);
723743
return status;
@@ -936,18 +956,15 @@ function createWindow() {
936956
});
937957
tray = new Tray(icon);
938958

939-
const contextMenu = Menu.buildFromTemplate([
940-
{ label: 'Item1', type: 'radio' },
941-
{ label: 'Item2', type: 'radio' },
942-
{ label: 'Item3', type: 'radio', checked: true },
943-
{ label: 'Item4', type: 'radio' }
944-
])
945-
tray.setToolTip('This is my application.')
946-
tray.setContextMenu(contextMenu)
959+
tray.on('click', () => {
960+
if (mainWindow) {
961+
mainWindow.show();
962+
}
963+
});
947964

948965
// Read the device code from the file (deviceCodeFilePath)
949966
// and send it to the renderer process
950-
readFilePromise(deviceCodeFilePath).then((deviceCodeBuffer) => {
967+
getFile(deviceCodeFilePath, '').then((deviceCodeBuffer) => {
951968
const deviceCode = deviceCodeBuffer.toString();
952969
console.log('Device code on ready: ', deviceCode);
953970
if (mainWindow) {
@@ -983,23 +1000,32 @@ app.on('activate', () => {
9831000

9841001
// This event will be emitted when your app is opened with a URL that uses your protocol
9851002
app.on('open-url', (event, url) => {
986-
// Prevent the default behavior
987-
event.preventDefault();
988-
989-
// Parse the URL
990-
const parsedUrl = new URL(url);
991-
const deviceCode = parsedUrl.host.split('=')[1];
992-
// Log the device code
993-
console.log(`Device code: ${deviceCode}`);
994-
995-
// Write the device code to a file in the sessionData directory
996-
writeFilePromise(deviceCodeFilePath, deviceCode).then(() => {
997-
console.log('Device code saved successfully!');
998-
});
1003+
try {
1004+
// Prevent the default behavior
1005+
event.preventDefault();
1006+
1007+
// Parse the URL
1008+
const parsedUrl = new URL(url);
1009+
const deviceCode = parsedUrl.host.split('=')[1];
1010+
// Log the device code
1011+
console.log(`Device code: ${deviceCode}`);
1012+
Sentry.captureMessage(`Device code added: ${deviceCode}, parsedUrl: ${JSON.stringify(parsedUrl)}`);
1013+
1014+
// Write the device code to a file in the sessionData directory
1015+
writeFilePromise(deviceCodeFilePath, deviceCode).then(() => {
1016+
console.log('Device code saved successfully!');
1017+
});
9991018

1000-
// Send the device code to the renderer process
1001-
if (mainWindow) {
1002-
mainWindow.webContents.send('device-code', deviceCode);
1019+
// Send the device code to the renderer process
1020+
if (mainWindow) {
1021+
mainWindow.webContents.send('device-code', deviceCode);
1022+
}
1023+
} catch (error: any) {
1024+
console.log(error)
1025+
Sentry.captureException(new Error(`Failed to open url: ${error?.message}`), {
1026+
tags: { module: "openUrl" },
1027+
extra: { error }
1028+
});
10031029
}
10041030
});
10051031

0 commit comments

Comments
 (0)