@@ -4,8 +4,10 @@ const { app, nativeTheme, nativeImage, BrowserWindow, Menu, Tray, screen, shell,
4
4
const path = require ( 'path' )
5
5
const fs = require ( 'fs' )
6
6
const request = require ( 'request' )
7
+ const https = require ( 'https' )
7
8
const extract = require ( 'extract-zip' )
8
9
const defaultMenu = require ( 'electron-default-menu' ) ;
10
+ const ProgressBar = require ( 'electron-progressbar' )
9
11
const { spawn, exec } = require ( 'child_process' ) ;
10
12
11
13
const helpers = require ( './helpers' )
@@ -54,14 +56,6 @@ if (isDev) {
54
56
logger . info ( 'Running the Electron app in dev mode.' )
55
57
}
56
58
57
- logger . info ( process . env )
58
- let appSettings = getAppSettings ( )
59
-
60
- let dimensions = { widIth : 1500 , height : 1000 } ;
61
-
62
- const contextMenu = require ( 'electron-context-menu' ) ;
63
- const { options } = require ( 'request' )
64
-
65
59
// Set the dock icon (MacOS and for development only)
66
60
if ( isMac && isDev ) {
67
61
const dockIcon = nativeImage . createFromPath (
@@ -70,6 +64,11 @@ if (isMac && isDev) {
70
64
app . dock . setIcon ( dockIcon )
71
65
}
72
66
67
+ let appSettings = getAppSettings ( )
68
+ let dimensions = { width : 1500 , height : 1000 } ;
69
+
70
+ // Modify the context menu
71
+ const contextMenu = require ( 'electron-context-menu' ) ;
73
72
contextMenu ( {
74
73
menu : ( actions ) => [
75
74
{
@@ -91,16 +90,102 @@ contextMenu({
91
90
]
92
91
} ) ;
93
92
93
+ // The standard quit item cannot be replaced / modified and it is not triggering the
94
+ // before-quit event on MacOS if a child window is open
95
+ const dockMenuWithforceQuit = Menu . buildFromTemplate ( [
96
+ {
97
+ label : 'Force Quit during download' ,
98
+ click : ( ) => {
99
+ // If the progress bar exists, close it
100
+ if ( progressBar ) {
101
+ progressBar . close ( ) ;
102
+ }
103
+ // Quit the app
104
+ app . quit ( ) ;
105
+ }
106
+ }
107
+ ] ) ;
108
+
109
+ // Download function with progress bar
110
+ let progressBar
94
111
const download = ( uri , filename , callback ) => {
95
- request . head ( uri , ( err , res , body ) => {
96
- logger . info ( 'content-type:' , res . headers [ 'content-type' ] )
97
- logger . info ( 'content-length:' , res . headers [ 'content-length' ] )
98
- if ( res . statusCode != 404 ) {
99
- request ( uri ) . pipe ( fs . createWriteStream ( filename ) ) . on ( 'close' , callback )
100
- } else {
101
- callback ( true )
112
+ // HEAD request first
113
+ request . head ( uri , ( err , res , body ) => {
114
+ if ( res . statusCode != 404 ) {
115
+ let receivedBytes = 0
116
+ const totalBytes = res . headers [ 'content-length' ]
117
+ logger . info ( `Total size to download: ${ totalBytes } ` )
118
+ progressBar = new ProgressBar ( {
119
+ indeterminate : false ,
120
+ abortOnError : true ,
121
+ text : 'Downloading the Specter binary from GitHub' ,
122
+ detail : 'This can take several minutes depending on your Internet connection. Specter will start once the download is finished.' ,
123
+ maxValue : totalBytes ,
124
+ browserWindow : {
125
+ parent : mainWindow
126
+ } ,
127
+ style : {
128
+ detail : {
129
+ 'margin-bottom' : '12px'
130
+ } ,
131
+ bar : {
132
+ 'background-color' : '#fff'
133
+ } ,
134
+ value : {
135
+ 'background-color' : '#000'
136
+ }
137
+ }
138
+ } )
139
+
140
+ // Add Force Quit item during download for MacOS dock
141
+ if ( isMac ) {
142
+ app . dock . setMenu ( dockMenuWithforceQuit ) ;
102
143
}
103
- } )
144
+
145
+ progressBar . on ( 'completed' , ( ) => {
146
+ progressBar . close ( )
147
+ // Remove the Force Quit dock item again for Mac
148
+ if ( isMac ) {
149
+ const updatedDockMenu = Menu . buildFromTemplate (
150
+ dockMenuWithforceQuit . items . filter ( item => item . label !== 'Force Quit during download' )
151
+ ) ;
152
+ app . dock . setMenu ( updatedDockMenu ) ;
153
+ }
154
+ } ) ;
155
+
156
+ progressBar . on ( 'aborted' , ( ) => {
157
+ logger . info ( 'Download was aborted before it could finish.' )
158
+ progressBar = null
159
+ } ) ;
160
+
161
+ // Loggin the download progress
162
+ let lastLogTime = 0 ;
163
+ const logInterval = 5000 ; // log every 5 seconds
164
+ progressBar . on ( 'progress' , ( ) => {
165
+ const currentTime = Date . now ( ) ;
166
+ if ( currentTime - lastLogTime >= logInterval ) {
167
+ lastLogTime = currentTime ;
168
+ logger . info ( `Download status: ${ ( receivedBytes / totalBytes * 100 ) . toFixed ( 0 ) } %` ) ;
169
+ }
170
+ } ) ;
171
+
172
+ // GET request
173
+ request ( uri )
174
+ . on ( 'data' , ( chunk ) => {
175
+ receivedBytes += chunk . length
176
+ if ( progressBar ) {
177
+ progressBar . value = receivedBytes
178
+ }
179
+ } )
180
+ . pipe ( fs . createWriteStream ( filename ) )
181
+ . on ( 'close' , callback )
182
+ }
183
+ // If the download link was not found, call callback (updatingLoaderMsg with error feedback)
184
+ else {
185
+ logger . info ( `Error while trying to download specterd: ${ err } ` )
186
+ callback ( true )
187
+ }
188
+ } )
104
189
}
105
190
106
191
let specterdProcess
@@ -253,11 +338,9 @@ app.whenReady().then(() => {
253
338
if ( fs . existsSync ( specterdPath + ( platformName == 'win64' ? '.exe' : '' ) ) ) {
254
339
getFileHash ( specterdPath + ( platformName == 'win64' ? '.exe' : '' ) , function ( specterdHash ) {
255
340
if ( appSettings . specterdHash . toLowerCase ( ) == specterdHash || appSettings . specterdHash == "" ) {
256
-
257
341
startSpecterd ( specterdPath )
258
342
} else if ( appSettings . specterdVersion != "" ) {
259
- updatingLoaderMsg ( 'Specterd version could not be validated. Retrying fetching specterd...' )
260
- updateSpecterdStatus ( 'Fetching Specter binary...' )
343
+ updatingLoaderMsg ( 'Specterd version could not be validated. Trying again to download the Specter binary ...' )
261
344
downloadSpecterd ( specterdPath )
262
345
} else {
263
346
updatingLoaderMsg ( 'Specterd file could not be validated and no version is configured in the settings<br>Please go to Preferences and set version to fetch or add an executable manually...' )
@@ -308,21 +391,20 @@ function initMainWindow() {
308
391
}
309
392
310
393
function downloadSpecterd ( specterdPath ) {
311
- updatingLoaderMsg ( `Fetching the ${ appName } binary.<br>This might take a minute...` )
312
- updateSpecterdStatus ( `Fetching ${ appName } binary...` )
394
+ updatingLoaderMsg ( `Starting download` )
395
+ updateSpecterdStatus ( `Downloading the ${ appName } binary...` )
396
+ // Some logging
313
397
logger . info ( "Using version " + appSettings . specterdVersion ) ;
314
398
logger . info ( "Using platformName " + platformName ) ;
315
-
316
399
download_location = getDownloadLocation ( appSettings . specterdVersion , platformName )
317
400
logger . info ( "Downloading from " + download_location ) ;
318
401
download ( download_location , specterdPath + '.zip' , function ( errored ) {
319
402
if ( errored == true ) {
320
- updatingLoaderMsg ( `Fetching ${ appNameLower } binary from the server failed, could not reach the server or the file could not have been found.` )
321
- updateSpecterdStatus ( `Fetching ${ appNameLower } d failed...` )
403
+ updatingLoaderMsg ( `Downloading the ${ appNameLower } binary from GitHub failed, could not reach the server or the file wasn't found.` )
404
+ updateSpecterdStatus ( `Downloading ${ appNameLower } d failed...` )
322
405
return
323
406
}
324
-
325
- updatingLoaderMsg ( 'Unpacking files...' )
407
+ updatingLoaderMsg ( 'Download completed. Unpacking files...' )
326
408
logger . info ( "Extracting " + specterdPath ) ;
327
409
328
410
extract ( specterdPath + '.zip' , { dir : specterdPath + '-dir' } ) . then ( function ( ) {
@@ -341,7 +423,6 @@ function downloadSpecterd(specterdPath) {
341
423
var newPath = specterdPath + ( platformName == 'win64' ? '.exe' : '' )
342
424
343
425
fs . renameSync ( oldPath , newPath )
344
- updatingLoaderMsg ( 'Cleaning up...' )
345
426
fs . unlinkSync ( specterdPath + '.zip' )
346
427
fs . rmdirSync ( specterdPath + '-dir' , { recursive : true } ) ;
347
428
getFileHash ( specterdPath + ( platformName == 'win64' ? '.exe' : '' ) , function ( specterdHash ) {
@@ -352,10 +433,6 @@ function downloadSpecterd(specterdPath) {
352
433
logger . error ( `hash of downloaded file: ${ specterdHash } ` )
353
434
logger . error ( `Expected hash: ${ appSettings . specterdHash } ` )
354
435
updateSpecterdStatus ( 'Failed to launch specterd...' )
355
-
356
- // app.quit()
357
- // TODO: This should never happen unless the specterd file was swapped on GitHub.
358
- // Think of what would be the appropriate way to handle this...
359
436
}
360
437
} )
361
438
} )
@@ -520,17 +597,21 @@ app.on('window-all-closed', function(){
520
597
}
521
598
} ) ;
522
599
523
- app . on ( 'before-quit' , ( ) => {
600
+ app . on ( 'before-quit' , ( event ) => {
524
601
if ( ! quitted ) {
602
+ logger . info ( 'Quitting ...' )
525
603
quitted = true
526
604
quitSpecterd ( )
527
-
528
605
if ( mainWindow && ! mainWindow . isDestroyed ( ) ) {
606
+ if ( progressBar ) {
607
+ progressBar . destroy ( )
608
+ progressBar = null
609
+ }
529
610
mainWindow . destroy ( )
530
611
mainWindow = null
531
612
prefWindow = null
532
613
tray = null
533
- }
614
+ }
534
615
}
535
616
} )
536
617
0 commit comments