@@ -15,7 +15,7 @@ import {
15
15
import { randomBytes } from "crypto"
16
16
import { release } from "os"
17
17
import { EventEmitter } from "events"
18
- import { mkdir , outputFile , readFile , rename , unlink } from "fs-extra"
18
+ import { mkdir , outputFile , readFile , rename , unlink , copyFile , pathExists } from "fs-extra"
19
19
import { OutgoingHttpHeaders } from "http"
20
20
import { load } from "js-yaml"
21
21
import { Lazy } from "lazy-val"
@@ -31,7 +31,7 @@ import { Provider, ProviderPlatform } from "./providers/Provider"
31
31
import type { TypedEmitter } from "tiny-typed-emitter"
32
32
import Session = Electron . Session
33
33
import type { AuthInfo } from "electron"
34
- import { gunzipSync } from "zlib"
34
+ import { gunzipSync , gzipSync } from "zlib"
35
35
import { blockmapFiles } from "./util"
36
36
import { DifferentialDownloaderOptions } from "./differentialDownloader/DifferentialDownloader"
37
37
import { GenericDifferentialDownloader } from "./differentialDownloader/GenericDifferentialDownloader"
@@ -117,6 +117,18 @@ export abstract class AppUpdater extends (EventEmitter as new () => TypedEmitter
117
117
*/
118
118
forceDevUpdateConfig = false
119
119
120
+ /**
121
+ * The base URL of the old block map file.
122
+ *
123
+ * When null, the updater will use the base URL of the update file to download the update.
124
+ * When set, the updater will use this string as the base URL of the old block map file.
125
+ * Some servers like github cannot download the old block map file from latest release,
126
+ * so you need to compute the old block map file base URL manually.
127
+ *
128
+ * @default null
129
+ */
130
+ public previousBlockmapBaseUrlOverride : string | null = null
131
+
120
132
/**
121
133
* The current application version.
122
134
*/
@@ -736,6 +748,10 @@ export abstract class AppUpdater extends (EventEmitter as new () => TypedEmitter
736
748
...updateInfo ,
737
749
downloadedFile : updateFile ,
738
750
} )
751
+ const currentBlockMapFile = path . join ( cacheDir , "current.blockmap" )
752
+ if ( await pathExists ( currentBlockMapFile ) ) {
753
+ await copyFile ( currentBlockMapFile , path . join ( downloadedUpdateHelper . cacheDir , "current.blockmap" ) )
754
+ }
739
755
return packageFile == null ? [ updateFile ] : [ updateFile , packageFile ]
740
756
}
741
757
@@ -790,7 +806,7 @@ export abstract class AppUpdater extends (EventEmitter as new () => TypedEmitter
790
806
if ( this . _testOnlyOptions != null && ! this . _testOnlyOptions . isUseDifferentialDownload ) {
791
807
return true
792
808
}
793
- const blockmapFileUrls = blockmapFiles ( fileInfo . url , this . app . version , downloadUpdateOptions . updateInfoAndProvider . info . version )
809
+ const blockmapFileUrls = blockmapFiles ( fileInfo . url , this . app . version , downloadUpdateOptions . updateInfoAndProvider . info . version , this . previousBlockmapBaseUrlOverride )
794
810
this . _logger . info ( `Download block maps (old: "${ blockmapFileUrls [ 0 ] } ", new: ${ blockmapFileUrls [ 1 ] } )` )
795
811
796
812
const downloadBlockMap = async ( url : URL ) : Promise < BlockMap > => {
@@ -824,8 +840,33 @@ export abstract class AppUpdater extends (EventEmitter as new () => TypedEmitter
824
840
downloadOptions . onProgress = it => this . emit ( DOWNLOAD_PROGRESS , it )
825
841
}
826
842
827
- const blockMapDataList = await Promise . all ( blockmapFileUrls . map ( u => downloadBlockMap ( u ) ) )
828
- await new GenericDifferentialDownloader ( fileInfo . info , this . httpExecutor , downloadOptions ) . download ( blockMapDataList [ 0 ] , blockMapDataList [ 1 ] )
843
+ const saveBlockMapToCacheDir = async ( blockMapData : BlockMap , cacheDir : string ) => {
844
+ const blockMapFile = path . join ( cacheDir , "current.blockmap" )
845
+ await outputFile ( blockMapFile , gzipSync ( JSON . stringify ( blockMapData ) ) )
846
+ }
847
+
848
+ const getBlockMapFromCacheDir = async ( cacheDir : string ) => {
849
+ const blockMapFile = path . join ( cacheDir , "current.blockmap" )
850
+ try {
851
+ if ( await pathExists ( blockMapFile ) ) {
852
+ return JSON . parse ( gunzipSync ( await readFile ( blockMapFile ) ) . toString ( ) )
853
+ }
854
+ } catch ( e : any ) {
855
+ this . _logger . warn ( `Cannot parse blockmap "${ blockMapFile } ", error: ${ e } ` )
856
+ }
857
+ return null
858
+ }
859
+
860
+ const newBlockMapData = await downloadBlockMap ( blockmapFileUrls [ 1 ] )
861
+ await saveBlockMapToCacheDir ( newBlockMapData , this . downloadedUpdateHelper ! . cacheDirForPendingUpdate )
862
+
863
+ // get old blockmap from cache dir first, if not found, download it
864
+ let oldBlockMapData = await getBlockMapFromCacheDir ( this . downloadedUpdateHelper ! . cacheDir )
865
+ if ( oldBlockMapData == null ) {
866
+ oldBlockMapData = await downloadBlockMap ( blockmapFileUrls [ 0 ] )
867
+ }
868
+
869
+ await new GenericDifferentialDownloader ( fileInfo . info , this . httpExecutor , downloadOptions ) . download ( oldBlockMapData , newBlockMapData )
829
870
return false
830
871
} catch ( e : any ) {
831
872
this . _logger . error ( `Cannot download differentially, fallback to full download: ${ e . stack || e } ` )
0 commit comments