@@ -10,14 +10,61 @@ import { writeFile as writeFilePromise, readFile as readFilePromise, unlink as u
1010import path from 'node:path'
1111import got from "got" ;
1212import cp from 'child_process' ;
13- import { MacWindow , UploadLink , baseUrl } from '../src/utils' ;
13+ import { MacWindow , UploadLink , baseUrl , Account , Preference } from '../src/utils' ;
1414import { platform } from 'process' ;
1515
16+ const sessionDataPath = app . getPath ( 'sessionData' ) ;
17+ const deviceCodeFilePath = path . join ( sessionDataPath , 'deviceCode.txt' ) ;
18+ const userAccountFilePath = path . join ( sessionDataPath , 'userAccount.txt' ) ;
19+ const userPreferencesFilePath = path . join ( sessionDataPath , 'userPreferences.txt' ) ;
20+
21+
1622autoUpdater . logger = logger
17- console . log ( `dsn: ${ process . env . SENTRY_DSN } ` )
1823Sentry . init ( {
1924 dsn : 'https://d9c49d59e5554239ac977e3a7c409cda@glitchtip.dermot.email/2'
2025} ) ;
26+
27+ const getPreferences = async ( ) : Promise < Preference [ ] | null > => {
28+ try {
29+ const preferences = await readFilePromise ( userPreferencesFilePath , 'utf-8' ) ;
30+ let parsed = JSON . parse ( preferences ) as Preference [ ] ?? [ ] ;
31+ if ( ! Array . isArray ( parsed ) ) return [ ] ;
32+
33+ // Remove duplicates based on Preference.name
34+ const uniquePreferences = Array . from ( new Map ( parsed . map ( preference => [ preference . name , preference ] ) ) . values ( ) ) ;
35+ return uniquePreferences ;
36+ } catch ( error : any ) {
37+ console . log ( error )
38+ Sentry . captureException ( new Error ( `Failed to get preferences: ${ error ?. message } ` ) , {
39+ tags : { module : "getPreferences" } ,
40+ extra : { error }
41+ } ) ;
42+ return null ;
43+ }
44+ } ;
45+
46+ const getPreference = async ( key : string ) : Promise < Preference [ 'value' ] | null > => {
47+ try {
48+ const preferences = await getPreferences ( ) ;
49+ console . log ( { preferences } )
50+ return preferences ?. find ( preference => preference . name === key ) ?. value ?? null
51+ } catch ( error : any ) {
52+ console . log ( error ) ;
53+ return null
54+ }
55+ } ;
56+
57+ getPreference ( 'errorLoggingEnabled' ) . then ( ( errorLoggingEnabled : string | boolean | null ) => {
58+ // Disable error logging if the preference is set to false
59+ if ( errorLoggingEnabled !== null && errorLoggingEnabled === false ) {
60+ const client = Sentry . getCurrentHub ( ) . getClient ( ) ;
61+ const options = client ?. getOptions ( ) ;
62+ if ( options ) {
63+ options . enabled = false ;
64+ }
65+ }
66+ } ) ;
67+
2168logger . info ( 'App starting...' ) ;
2269
2370import ffmpeg from 'fluent-ffmpeg' ;
@@ -35,11 +82,6 @@ let tray: Tray | null = null
3582// recording state
3683let showCameraWindow = false ;
3784
38- const sessionDataPath = app . getPath ( 'sessionData' ) ;
39- const deviceCodeFilePath = path . join ( sessionDataPath , 'deviceCode.txt' ) ;
40-
41- // myUndefinedFunction();
42-
4385function getComputerName ( ) {
4486 switch ( process . platform ) {
4587 case "win32" :
@@ -54,6 +96,20 @@ function getComputerName() {
5496 }
5597}
5698
99+ const refreshWindows = ( ) => {
100+ try {
101+ if ( mainWindow ) mainWindow ?. webContents . send ( 'set-window' , 'main' )
102+ if ( floatingWindow ) floatingWindow ?. webContents . send ( 'set-window' , 'floating' )
103+ if ( webcamWindow ) webcamWindow ?. webContents . send ( 'set-window' , 'webcam' )
104+ } catch ( error : any ) {
105+ console . log ( error )
106+ Sentry . captureException ( new Error ( `Failed to refresh: ${ error ?. message } ` ) , {
107+ tags : { module : "refreshWindows" } ,
108+ extra : { error }
109+ } ) ;
110+ }
111+ } ;
112+
57113ipcMain . handle ( 'get-desktop-capturer-sources' , async ( ) => {
58114 const screenSources = await desktopCapturer . getSources ( { types : [ 'screen' ] , fetchWindowIcons : true , thumbnailSize : { width : 1920 , height : 1080 } } )
59115 const windowSources = await desktopCapturer . getSources ( { types : [ 'window' , ] , fetchWindowIcons : true , thumbnailSize : { width : 1920 , height : 1080 } } )
@@ -164,6 +220,7 @@ ipcMain.handle('stop-recording', async (_) => {
164220 if ( webcamWindow ) {
165221 toggleCameraWindow ( true ) ;
166222 webcamWindow . setAlwaysOnTop ( false ) ;
223+ webcamWindow . minimize ( ) ;
167224 webcamWindow . hide ( ) ;
168225 }
169226 if ( mainWindow ) {
@@ -412,18 +469,12 @@ const toggleCameraWindow = (show: boolean) => {
412469const verifyDeviceCode = async ( deviceCode : string ) => {
413470 try {
414471 const url = `${ baseUrl } /api/devices/verify` ;
415- const response = await fetch ( url , {
416- method : 'POST' ,
417- headers : {
418- 'Content-Type' : 'application/json'
419- } ,
420- body : JSON . stringify ( { deviceCode } )
421- } ) ;
472+ const response = await axios . post ( url , { deviceCode } ) ;
422473 if ( response . status !== 200 ) {
423474 console . log ( JSON . stringify ( { e : "failed to verify device code" , url } ) )
424475 throw new Error ( response . statusText ) ;
425476 }
426- const data = await response . json ( ) ;
477+ const data = response . data ;
427478 Sentry . setUser ( { userId : data ?. id , deviceName : data ?. name , projectId : data ?. user ?. currentProjectId , name : data ?. user ?. name , email : data ?. user ?. email } )
428479
429480 if ( data . error ) {
@@ -466,58 +517,115 @@ const getDeviceCode = async () => {
466517 }
467518}
468519
469- const log = async ( data : object ) => {
470- const webhookUrl = 'https://webhook.site/ce05f4c4-7d74-4013-a954-356b11d11873' ;
471- try {
472- await fetch ( webhookUrl , {
473- method : 'POST' ,
474- headers : {
475- 'Content-Type' : 'application/json'
476- } ,
477- body : JSON . stringify ( data )
478- } ) ;
479- } catch ( error : any ) {
480- console . error ( 'Failed to send log:' , error ) ;
481- Sentry . captureException ( new Error ( `Failed to send log: ${ error ?. message } ` ) , {
482- tags : { module : "log" } ,
483- extra : { error }
484- } ) ;
485- }
486- }
487-
488- const getAccount = async ( ) => {
520+ const getAccount = async ( ) : Promise < Account | null > => {
489521 try {
522+ // Check if user has a device code (login status)
490523 const deviceCode = await getDeviceCode ( ) ;
491524 if ( deviceCode === '' || ! deviceCode ) {
492525 if ( mainWindow ) {
493526 mainWindow . webContents . send ( 'device-code' , '' ) ;
494527 }
495- return ;
528+ return null ;
529+ }
530+
531+ // Auth cache stored for 5 minutes
532+ const userAccountFileBuffer = await readFilePromise ( userAccountFilePath ) ;
533+ const userAccount : Account = JSON . parse ( userAccountFileBuffer . toString ( ) ) ;
534+ // Check if the user account was updated less than 5 minutes ago
535+ const currentTime = new Date ( ) . getTime ( ) ;
536+ const lastUpdatedTime = new Date ( userAccount . lastUpdated ) . getTime ( ) ;
537+ const timeDifferenceInMinutes = ( currentTime - lastUpdatedTime ) / ( 1000 * 60 ) ;
538+ if ( timeDifferenceInMinutes < 5 ) {
539+ return userAccount ;
496540 }
497541
542+
498543 // Verify the device code
499- const device = await verifyDeviceCode ( deviceCode ) ;
544+ const device : Account = await verifyDeviceCode ( deviceCode ) ;
500545 if ( ! device ) {
501546 if ( mainWindow ) {
502547 mainWindow . webContents . send ( 'device-code' , '' ) ;
503548 Sentry . captureException ( new Error ( `Failed to get account: device not found` ) , {
504- tags : { module : "getAccount" } ,
505- extra : { deviceCode }
549+ tags : { module : "getAccount" , deviceCode } ,
506550 } ) ;
507551 }
508- return ;
552+ return null ;
509553 }
554+
555+ // Write the response to userAccountFilePath
556+ await writeFilePromise ( userAccountFilePath , JSON . stringify ( { ...device , lastUpdated : new Date ( ) } ) ) ;
557+
510558 return device ;
511559 } catch ( error : any ) {
512560 console . log ( error )
513561 Sentry . captureException ( new Error ( `Failed to get account: ${ error ?. message } ` ) , {
514562 tags : { module : "getAccount" } ,
515563 extra : { error }
516564 } ) ;
517- return ;
565+ return null ;
518566 }
519567}
520568
569+ ipcMain . handle ( 'get-account' , async ( _ ) => {
570+ try {
571+ const account = await getAccount ( ) ;
572+ return account ;
573+ } catch ( error : any ) {
574+ console . log ( error )
575+ Sentry . captureException ( new Error ( `Failed to get account: ${ error ?. message } ` ) , {
576+ tags : { module : "getAccount" } ,
577+ extra : { error }
578+ } ) ;
579+ return null ;
580+ }
581+ } ) ;
582+
583+
584+ const updatePreferences = async ( newPreferences : Preference [ ] ) : Promise < boolean > => {
585+ try {
586+ // Write upserted preferences back to file
587+ await writeFilePromise ( userPreferencesFilePath , JSON . stringify ( newPreferences ) ) ;
588+ return true ;
589+ } catch ( error : any ) {
590+ console . log ( error )
591+ Sentry . captureException ( new Error ( `Failed to upsert preferences: ${ error ?. message } ` ) , {
592+ tags : { module : "upsertPreferences" } ,
593+ extra : { error }
594+ } ) ;
595+ return false ;
596+ }
597+ } ;
598+
599+ ipcMain . handle ( 'get-preferences' , async ( _ ) => {
600+ try {
601+ const preferences = await getPreferences ( ) ;
602+ return preferences ;
603+ } catch ( error : any ) {
604+ console . log ( error )
605+ Sentry . captureException ( new Error ( `Failed to get preferences: ${ error ?. message } ` ) , {
606+ tags : { module : "getPreferences" } ,
607+ extra : { error }
608+ } ) ;
609+ return null ;
610+ }
611+ } ) ;
612+
613+ ipcMain . handle ( 'update-preferences' , async ( _event , newPreferences : Preference [ ] ) => {
614+ try {
615+ await updatePreferences ( newPreferences ) ;
616+ return true ;
617+ } catch ( error : any ) {
618+ console . log ( error )
619+ Sentry . captureException ( new Error ( `Failed to set preferences: ${ error ?. message } ` ) , {
620+ tags : { module : "setPreferences" } ,
621+ extra : { error }
622+ } ) ;
623+ return false ;
624+ }
625+ } ) ;
626+
627+
628+
521629ipcMain . handle ( 'get-device-code' , async ( _ ) => {
522630 try {
523631 const deviceCode = await getDeviceCode ( ) ;
@@ -543,6 +651,25 @@ ipcMain.handle('get-device-code', async (_) => {
543651 }
544652} ) ;
545653
654+ ipcMain . handle ( 'logout' , async ( _ ) => {
655+ try {
656+ // Clear the user account and device code
657+ await writeFilePromise ( userAccountFilePath , JSON . stringify ( { } ) ) ;
658+ await writeFilePromise ( deviceCodeFilePath , JSON . stringify ( { } ) ) ;
659+ // Send a logout event to the renderer process
660+ if ( mainWindow ) mainWindow . webContents . send ( 'device-code' , '' ) ;
661+ if ( floatingWindow ) floatingWindow . hide ( ) ;
662+ if ( webcamWindow ) webcamWindow . hide ( ) ;
663+ } catch ( error : any ) {
664+ console . log ( error )
665+ Sentry . captureException ( new Error ( `Failed to logout: ${ error ?. message } ` ) , {
666+ tags : { module : "logout" } ,
667+ extra : { error }
668+ } ) ;
669+ }
670+ } ) ;
671+
672+
546673ipcMain . handle ( 'permissions-missing' , async ( _ ) => {
547674 try {
548675 if ( mainWindow ) {
@@ -586,6 +713,10 @@ const missingPermissions = async () => {
586713 return missingList ;
587714}
588715
716+ setTimeout ( ( ) => {
717+ Sentry . captureException ( new Error ( `Testing sentry` ) ) ;
718+ } ) ;
719+
589720const requestPermissions = async ( permission : string ) : Promise < boolean > => {
590721 try {
591722 if ( permission === 'camera' || permission === 'microphone' ) {
@@ -822,6 +953,7 @@ function createWindow() {
822953 console . log ( 'Device code on ready: ' , deviceCode ) ;
823954 if ( mainWindow ) {
824955 mainWindow . webContents . send ( 'device-code' , deviceCode ) ;
956+ refreshWindows ( ) ;
825957 } else {
826958 console . log ( 'No window to send device code to' ) ;
827959 }
0 commit comments