|
1 |
| -import { AllPublishOptions, newError, PackageFileInfo, CURRENT_APP_INSTALLER_FILE_NAME, CURRENT_APP_PACKAGE_FILE_NAME } from "builder-util-runtime" |
| 1 | +import { AllPublishOptions, newError, PackageFileInfo, BlockMap, CURRENT_APP_PACKAGE_FILE_NAME, CURRENT_APP_INSTALLER_FILE_NAME } from "builder-util-runtime" |
2 | 2 | import * as path from "path"
|
3 | 3 | import { AppAdapter } from "./AppAdapter"
|
4 | 4 | import { DownloadUpdateOptions } from "./AppUpdater"
|
5 | 5 | import { BaseUpdater, InstallOptions } from "./BaseUpdater"
|
6 | 6 | import { DifferentialDownloaderOptions } from "./differentialDownloader/DifferentialDownloader"
|
7 | 7 | import { FileWithEmbeddedBlockMapDifferentialDownloader } from "./differentialDownloader/FileWithEmbeddedBlockMapDifferentialDownloader"
|
8 |
| -import { DOWNLOAD_PROGRESS, verifyUpdateCodeSignature } from "./main" |
| 8 | +import { GenericDifferentialDownloader } from "./differentialDownloader/GenericDifferentialDownloader" |
| 9 | +import { DOWNLOAD_PROGRESS, ResolvedUpdateFileInfo, verifyUpdateCodeSignature } from "./main" |
| 10 | +import { blockmapFiles } from "./util" |
9 | 11 | import { findFile, Provider } from "./providers/Provider"
|
10 | 12 | import { unlink } from "fs-extra"
|
11 | 13 | import { verifySignature } from "./windowsExecutableCodeSignatureVerifier"
|
12 | 14 | import { URL } from "url"
|
| 15 | +import { gunzipSync } from "zlib" |
13 | 16 |
|
14 | 17 | export class NsisUpdater extends BaseUpdater {
|
15 | 18 | /**
|
@@ -64,7 +67,7 @@ export class NsisUpdater extends BaseUpdater {
|
64 | 67 | if (
|
65 | 68 | isWebInstaller ||
|
66 | 69 | downloadUpdateOptions.disableDifferentialDownload ||
|
67 |
| - (await this.differentialDownloadInstaller(fileInfo, downloadUpdateOptions, destinationFile, provider, CURRENT_APP_INSTALLER_FILE_NAME)) |
| 70 | + (await this.differentialDownloadInstaller(fileInfo, downloadUpdateOptions, destinationFile, provider)) |
68 | 71 | ) {
|
69 | 72 | await this.httpExecutor.download(fileInfo.url, destinationFile, downloadOptions)
|
70 | 73 | }
|
@@ -173,6 +176,63 @@ export class NsisUpdater extends BaseUpdater {
|
173 | 176 | return true
|
174 | 177 | }
|
175 | 178 |
|
| 179 | + private async differentialDownloadInstaller( |
| 180 | + fileInfo: ResolvedUpdateFileInfo, |
| 181 | + downloadUpdateOptions: DownloadUpdateOptions, |
| 182 | + installerPath: string, |
| 183 | + provider: Provider<any> |
| 184 | + ): Promise<boolean> { |
| 185 | + try { |
| 186 | + if (this._testOnlyOptions != null && !this._testOnlyOptions.isUseDifferentialDownload) { |
| 187 | + return true |
| 188 | + } |
| 189 | + const blockmapFileUrls = blockmapFiles(fileInfo.url, this.app.version, downloadUpdateOptions.updateInfoAndProvider.info.version) |
| 190 | + this._logger.info(`Download block maps (old: "${blockmapFileUrls[0]}", new: ${blockmapFileUrls[1]})`) |
| 191 | + |
| 192 | + const downloadBlockMap = async (url: URL): Promise<BlockMap> => { |
| 193 | + const data = await this.httpExecutor.downloadToBuffer(url, { |
| 194 | + headers: downloadUpdateOptions.requestHeaders, |
| 195 | + cancellationToken: downloadUpdateOptions.cancellationToken, |
| 196 | + }) |
| 197 | + |
| 198 | + if (data == null || data.length === 0) { |
| 199 | + throw new Error(`Blockmap "${url.href}" is empty`) |
| 200 | + } |
| 201 | + |
| 202 | + try { |
| 203 | + return JSON.parse(gunzipSync(data).toString()) |
| 204 | + } catch (e: any) { |
| 205 | + throw new Error(`Cannot parse blockmap "${url.href}", error: ${e}`) |
| 206 | + } |
| 207 | + } |
| 208 | + |
| 209 | + const downloadOptions: DifferentialDownloaderOptions = { |
| 210 | + newUrl: fileInfo.url, |
| 211 | + oldFile: path.join(this.downloadedUpdateHelper!.cacheDir, CURRENT_APP_INSTALLER_FILE_NAME), |
| 212 | + logger: this._logger, |
| 213 | + newFile: installerPath, |
| 214 | + isUseMultipleRangeRequest: provider.isUseMultipleRangeRequest, |
| 215 | + requestHeaders: downloadUpdateOptions.requestHeaders, |
| 216 | + cancellationToken: downloadUpdateOptions.cancellationToken, |
| 217 | + } |
| 218 | + |
| 219 | + if (this.listenerCount(DOWNLOAD_PROGRESS) > 0) { |
| 220 | + downloadOptions.onProgress = it => this.emit(DOWNLOAD_PROGRESS, it) |
| 221 | + } |
| 222 | + |
| 223 | + const blockMapDataList = await Promise.all(blockmapFileUrls.map(u => downloadBlockMap(u))) |
| 224 | + await new GenericDifferentialDownloader(fileInfo.info, this.httpExecutor, downloadOptions).download(blockMapDataList[0], blockMapDataList[1]) |
| 225 | + return false |
| 226 | + } catch (e: any) { |
| 227 | + this._logger.error(`Cannot download differentially, fallback to full download: ${e.stack || e}`) |
| 228 | + if (this._testOnlyOptions != null) { |
| 229 | + // test mode |
| 230 | + throw e |
| 231 | + } |
| 232 | + return true |
| 233 | + } |
| 234 | + } |
| 235 | + |
176 | 236 | private async differentialDownloadWebPackage(
|
177 | 237 | downloadUpdateOptions: DownloadUpdateOptions,
|
178 | 238 | packageInfo: PackageFileInfo,
|
|
0 commit comments