Skip to content

Commit

Permalink
Revert "feat: add support for differential zip updates on macOS (#7709)"
Browse files Browse the repository at this point in the history
This reverts commit 79df542.
  • Loading branch information
mmaietta committed Mar 3, 2024
1 parent cb335ec commit e841f89
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 680 deletions.
62 changes: 0 additions & 62 deletions packages/electron-updater/src/AppUpdater.ts
Expand Up @@ -9,7 +9,6 @@ import {
DownloadOptions,
CancellationError,
ProgressInfo,
BlockMap,
} from "builder-util-runtime"
import { randomBytes } from "crypto"
import { EventEmitter } from "events"
Expand All @@ -30,10 +29,6 @@ import { ProviderPlatform } from "./providers/Provider"
import type { TypedEmitter } from "tiny-typed-emitter"
import Session = Electron.Session
import { AuthInfo } from "electron"
import { gunzipSync } from "zlib"
import { blockmapFiles } from "./util"
import { DifferentialDownloaderOptions } from "./differentialDownloader/DifferentialDownloader"
import { GenericDifferentialDownloader } from "./differentialDownloader/GenericDifferentialDownloader"

export type AppUpdaterEvents = {
error: (error: Error, message?: string) => void
Expand Down Expand Up @@ -702,63 +697,6 @@ export abstract class AppUpdater extends (EventEmitter as new () => TypedEmitter
log.info(`New version ${version} has been downloaded to ${updateFile}`)
return await done(true)
}
protected async differentialDownloadInstaller(
fileInfo: ResolvedUpdateFileInfo,
downloadUpdateOptions: DownloadUpdateOptions,
installerPath: string,
provider: Provider<any>,
oldInstallerFileName: string
): Promise<boolean> {
try {
if (this._testOnlyOptions != null && !this._testOnlyOptions.isUseDifferentialDownload) {
return true
}
const blockmapFileUrls = blockmapFiles(fileInfo.url, this.app.version, downloadUpdateOptions.updateInfoAndProvider.info.version)
this._logger.info(`Download block maps (old: "${blockmapFileUrls[0]}", new: ${blockmapFileUrls[1]})`)

const downloadBlockMap = async (url: URL): Promise<BlockMap> => {
const data = await this.httpExecutor.downloadToBuffer(url, {
headers: downloadUpdateOptions.requestHeaders,
cancellationToken: downloadUpdateOptions.cancellationToken,
})

if (data == null || data.length === 0) {
throw new Error(`Blockmap "${url.href}" is empty`)
}

try {
return JSON.parse(gunzipSync(data).toString())
} catch (e: any) {
throw new Error(`Cannot parse blockmap "${url.href}", error: ${e}`)
}
}

const downloadOptions: DifferentialDownloaderOptions = {
newUrl: fileInfo.url,
oldFile: path.join(this.downloadedUpdateHelper!.cacheDir, oldInstallerFileName),
logger: this._logger,
newFile: installerPath,
isUseMultipleRangeRequest: provider.isUseMultipleRangeRequest,
requestHeaders: downloadUpdateOptions.requestHeaders,
cancellationToken: downloadUpdateOptions.cancellationToken,
}

if (this.listenerCount(DOWNLOAD_PROGRESS) > 0) {
downloadOptions.onProgress = it => this.emit(DOWNLOAD_PROGRESS, it)
}

const blockMapDataList = await Promise.all(blockmapFileUrls.map(u => downloadBlockMap(u)))
await new GenericDifferentialDownloader(fileInfo.info, this.httpExecutor, downloadOptions).download(blockMapDataList[0], blockMapDataList[1])
return false
} catch (e: any) {
this._logger.error(`Cannot download differentially, fallback to full download: ${e.stack || e}`)
if (this._testOnlyOptions != null) {
// test mode
throw e
}
return true
}
}
}

export interface DownloadUpdateOptions {
Expand Down
41 changes: 7 additions & 34 deletions packages/electron-updater/src/MacUpdater.ts
@@ -1,7 +1,6 @@
import { AllPublishOptions, newError, safeStringifyJson } from "builder-util-runtime"
import { pathExistsSync, stat } from "fs-extra"
import { createReadStream, copyFileSync } from "fs"
import * as path from "path"
import { stat } from "fs-extra"
import { createReadStream } from "fs"
import { createServer, IncomingMessage, Server, ServerResponse } from "http"
import { AppAdapter } from "./AppAdapter"
import { AppUpdater, DownloadUpdateOptions } from "./AppUpdater"
Expand All @@ -27,7 +26,6 @@ export class MacUpdater extends AppUpdater {
})
this.nativeUpdater.on("update-downloaded", () => {
this.squirrelDownloadedUpdate = true
this.debug("nativeUpdater.update-downloaded")
})
}

Expand All @@ -37,17 +35,6 @@ export class MacUpdater extends AppUpdater {
}
}

private closeServerIfExists() {
if (this.server) {
this.debug("Closing proxy server")
this.server.close(err => {
if (err) {
this.debug("proxy server wasn't already open, probably attempted closing again as a safety check before quit")
}
})
}
}

protected async doDownloadUpdate(downloadUpdateOptions: DownloadUpdateOptions): Promise<Array<string>> {
let files = downloadUpdateOptions.updateInfoAndProvider.provider.resolveFiles(downloadUpdateOptions.updateInfoAndProvider.info)

Expand Down Expand Up @@ -92,26 +79,12 @@ export class MacUpdater extends AppUpdater {
throw newError(`ZIP file not provided: ${safeStringifyJson(files)}`, "ERR_UPDATER_ZIP_FILE_NOT_FOUND")
}

const provider = downloadUpdateOptions.updateInfoAndProvider.provider
const CURRENT_MAC_APP_ZIP_FILE_NAME = "update.zip"

return this.executeDownload({
fileExtension: "zip",
fileInfo: zipFileInfo,
downloadUpdateOptions,
task: async (destinationFile, downloadOptions) => {
const cachedFile = path.join(this.downloadedUpdateHelper!.cacheDir, CURRENT_MAC_APP_ZIP_FILE_NAME)
const canDifferentialDownload = () => {
if (!pathExistsSync(cachedFile)) {
log.info("Unable to locate previous update.zip for differential download (is this first install?), falling back to full download")
return false
}
return !downloadUpdateOptions.disableDifferentialDownload
}
if (canDifferentialDownload() && (await this.differentialDownloadInstaller(zipFileInfo, downloadUpdateOptions, destinationFile, provider, CURRENT_MAC_APP_ZIP_FILE_NAME))) {
await this.httpExecutor.download(zipFileInfo.url, destinationFile, downloadOptions)
}
copyFileSync(destinationFile, cachedFile)
task: (destinationFile, downloadOptions) => {
return this.httpExecutor.download(zipFileInfo.url, destinationFile, downloadOptions)
},
done: event => this.updateDownloaded(zipFileInfo, event),
})
Expand All @@ -123,8 +96,8 @@ export class MacUpdater extends AppUpdater {

const log = this._logger
const logContext = `fileToProxy=${zipFileInfo.url.href}`
this.closeServerIfExists()
this.debug(`Creating proxy server for native Squirrel.Mac (${logContext})`)
this.server?.close()
this.server = createServer()
this.debug(`Proxy server for native Squirrel.Mac is created (${logContext})`)
this.server.on("close", () => {
Expand Down Expand Up @@ -243,12 +216,12 @@ export class MacUpdater extends AppUpdater {
if (this.squirrelDownloadedUpdate) {
// update already fetched by Squirrel, it's ready to install
this.nativeUpdater.quitAndInstall()
this.closeServerIfExists()
this.server?.close()
} else {
// Quit and install as soon as Squirrel get the update
this.nativeUpdater.on("update-downloaded", () => {
this.nativeUpdater.quitAndInstall()
this.closeServerIfExists()
this.server?.close()
})

if (!this.autoInstallOnAppQuit) {
Expand Down
66 changes: 63 additions & 3 deletions packages/electron-updater/src/NsisUpdater.ts
@@ -1,15 +1,18 @@
import { AllPublishOptions, newError, PackageFileInfo, CURRENT_APP_INSTALLER_FILE_NAME, CURRENT_APP_PACKAGE_FILE_NAME } from "builder-util-runtime"
import { AllPublishOptions, newError, PackageFileInfo, BlockMap, CURRENT_APP_PACKAGE_FILE_NAME, CURRENT_APP_INSTALLER_FILE_NAME } from "builder-util-runtime"
import * as path from "path"
import { AppAdapter } from "./AppAdapter"
import { DownloadUpdateOptions } from "./AppUpdater"
import { BaseUpdater, InstallOptions } from "./BaseUpdater"
import { DifferentialDownloaderOptions } from "./differentialDownloader/DifferentialDownloader"
import { FileWithEmbeddedBlockMapDifferentialDownloader } from "./differentialDownloader/FileWithEmbeddedBlockMapDifferentialDownloader"
import { DOWNLOAD_PROGRESS, verifyUpdateCodeSignature } from "./main"
import { GenericDifferentialDownloader } from "./differentialDownloader/GenericDifferentialDownloader"
import { DOWNLOAD_PROGRESS, ResolvedUpdateFileInfo, verifyUpdateCodeSignature } from "./main"
import { blockmapFiles } from "./util"
import { findFile, Provider } from "./providers/Provider"
import { unlink } from "fs-extra"
import { verifySignature } from "./windowsExecutableCodeSignatureVerifier"
import { URL } from "url"
import { gunzipSync } from "zlib"

export class NsisUpdater extends BaseUpdater {
/**
Expand Down Expand Up @@ -64,7 +67,7 @@ export class NsisUpdater extends BaseUpdater {
if (
isWebInstaller ||
downloadUpdateOptions.disableDifferentialDownload ||
(await this.differentialDownloadInstaller(fileInfo, downloadUpdateOptions, destinationFile, provider, CURRENT_APP_INSTALLER_FILE_NAME))
(await this.differentialDownloadInstaller(fileInfo, downloadUpdateOptions, destinationFile, provider))
) {
await this.httpExecutor.download(fileInfo.url, destinationFile, downloadOptions)
}
Expand Down Expand Up @@ -173,6 +176,63 @@ export class NsisUpdater extends BaseUpdater {
return true
}

private async differentialDownloadInstaller(
fileInfo: ResolvedUpdateFileInfo,
downloadUpdateOptions: DownloadUpdateOptions,
installerPath: string,
provider: Provider<any>
): Promise<boolean> {
try {
if (this._testOnlyOptions != null && !this._testOnlyOptions.isUseDifferentialDownload) {
return true
}
const blockmapFileUrls = blockmapFiles(fileInfo.url, this.app.version, downloadUpdateOptions.updateInfoAndProvider.info.version)
this._logger.info(`Download block maps (old: "${blockmapFileUrls[0]}", new: ${blockmapFileUrls[1]})`)

const downloadBlockMap = async (url: URL): Promise<BlockMap> => {
const data = await this.httpExecutor.downloadToBuffer(url, {
headers: downloadUpdateOptions.requestHeaders,
cancellationToken: downloadUpdateOptions.cancellationToken,
})

if (data == null || data.length === 0) {
throw new Error(`Blockmap "${url.href}" is empty`)
}

try {
return JSON.parse(gunzipSync(data).toString())
} catch (e: any) {
throw new Error(`Cannot parse blockmap "${url.href}", error: ${e}`)
}
}

const downloadOptions: DifferentialDownloaderOptions = {
newUrl: fileInfo.url,
oldFile: path.join(this.downloadedUpdateHelper!.cacheDir, CURRENT_APP_INSTALLER_FILE_NAME),
logger: this._logger,
newFile: installerPath,
isUseMultipleRangeRequest: provider.isUseMultipleRangeRequest,
requestHeaders: downloadUpdateOptions.requestHeaders,
cancellationToken: downloadUpdateOptions.cancellationToken,
}

if (this.listenerCount(DOWNLOAD_PROGRESS) > 0) {
downloadOptions.onProgress = it => this.emit(DOWNLOAD_PROGRESS, it)
}

const blockMapDataList = await Promise.all(blockmapFileUrls.map(u => downloadBlockMap(u)))
await new GenericDifferentialDownloader(fileInfo.info, this.httpExecutor, downloadOptions).download(blockMapDataList[0], blockMapDataList[1])
return false
} catch (e: any) {
this._logger.error(`Cannot download differentially, fallback to full download: ${e.stack || e}`)
if (this._testOnlyOptions != null) {
// test mode
throw e
}
return true
}
}

private async differentialDownloadWebPackage(
downloadUpdateOptions: DownloadUpdateOptions,
packageInfo: PackageFileInfo,
Expand Down

0 comments on commit e841f89

Please sign in to comment.