Skip to content

Commit

Permalink
feat(electron-updater): abort download
Browse files Browse the repository at this point in the history
Close #1150
  • Loading branch information
develar committed Feb 17, 2017
1 parent ae036c6 commit 91613a9
Showing 73 changed files with 495 additions and 417 deletions.
4 changes: 2 additions & 2 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@
[
"transform-async-to-module-method",
{
module: "bluebird-lst-c",
module: "bluebird-lst",
method: "coroutine"
}
],
@@ -27,7 +27,7 @@
[
"transform-async-to-module-method",
{
module: "bluebird-lst-c",
module: "bluebird-lst",
method: "coroutine"
}
],
1 change: 1 addition & 0 deletions .idea/dictionaries/develar.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 0 additions & 12 deletions .idea/runConfigurations/compile.xml

This file was deleted.

12 changes: 0 additions & 12 deletions .idea/runConfigurations/lint.xml

This file was deleted.

12 changes: 0 additions & 12 deletions .idea/runConfigurations/test.xml

This file was deleted.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -26,15 +26,15 @@
"7zip-bin": "^2.0.4",
"archiver": "^1.3.0",
"asar-electron-builder": "^0.13.5",
"aws-sdk": "^2.13.0",
"bluebird-lst-c": "^1.0.6",
"aws-sdk": "^2.15.0",
"bluebird-lst": "^1.0.1",
"chalk": "^1.1.3",
"chromium-pickle-js": "^0.2.0",
"cuint": "^0.2.2",
"debug": "^2.6.1",
"electron-download-tf": "3.2.0",
"electron-macos-sign": "~1.6.0",
"fs-extra-p": "^3.1.0",
"fs-extra-p": "^4.0.1",
"hosted-git-info": "^2.2.0",
"ini": "^1.3.4",
"is-ci": "^1.0.10",
@@ -80,7 +80,7 @@
"lerna": "2.0.0-beta.37",
"path-sort": "^0.1.0",
"source-map-support": "^0.4.11",
"ts-babel": "^1.3.6",
"ts-babel": "^1.3.7",
"tslint": "^4.4.2",
"typescript": "^2.2.0",
"typescript-json-schema": "^0.9.0",
2 changes: 1 addition & 1 deletion packages/electron-builder-http/package.json
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@
"//": "client can also install js-yaml to load yaml",
"dependencies": {
"debug": "2.6.1",
"fs-extra-p": "^3.1.0"
"fs-extra-p": "^4.0.1"
},
"typings": "./out/electron-builder-http.d.ts"
}
89 changes: 80 additions & 9 deletions packages/electron-builder-http/src/CancellationToken.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,108 @@
import BluebirdPromise from "bluebird-lst"
import { EventEmitter } from "events"
import BluebirdPromise from "bluebird-lst-c"

export class CancellationToken extends EventEmitter {
private parentCancelHandler: any | null = null

private _cancelled: boolean
get cancelled(): boolean {
return this._cancelled || (this._parent != null && this._parent.cancelled)
}

private _parent: CancellationToken | null
set parent(value: CancellationToken) {
this.removeParentCancelHandler()

this._parent = value
this.parentCancelHandler = () => this.cancel()
this._parent.onCancel(this.parentCancelHandler)
}

// babel cannot compile ... correctly for super calls
constructor() {
constructor(parent?: CancellationToken) {
super()

this._cancelled = false
if (parent != null) {
this.parent = parent
}
}

cancel() {
this._cancelled = true
this.emit("cancel")
}

onCancel(handler: () => any) {
this.once("cancel", handler)
private onCancel(handler: () => any) {
if (this.cancelled) {
handler()
}
else {
this.once("cancel", handler)
}
}

trackPromise(promise: BluebirdPromise<any>): BluebirdPromise<any> {
const handler = () => promise.cancel()
this.onCancel(handler)
// it is important to return promise, otherwise will be unhandled rejection error on reject
return promise.finally(() => this.removeListener("cancel", handler))
createPromise<R>(callback: (resolve: (thenableOrResult?: R) => void, reject: (error?: any) => void, onCancel: (callback: () => void) => void) => void): Promise<R> {
if (this.cancelled) {
return BluebirdPromise.reject(new CancellationError())
}

let cancelHandler: (() => void) | null = null
return new BluebirdPromise((resolve, reject) => {
let addedCancelHandler: (() => void) | null = null

cancelHandler = () => {
try {
if (addedCancelHandler != null) {
addedCancelHandler()
addedCancelHandler = null
}
}
finally {
reject(new CancellationError())
}
}

if (this.cancelled) {
cancelHandler()
return
}

this.onCancel(cancelHandler)

callback(resolve, reject, (callback: () => void) => {
addedCancelHandler = callback
})
})
.finally(() => {
if (cancelHandler != null) {
this.removeListener("cancel", cancelHandler)
cancelHandler = null
}
})
}

private removeParentCancelHandler() {
const parent = this._parent
if (parent != null && this.parentCancelHandler != null) {
parent.removeListener("cancel", this.parentCancelHandler)
this.parentCancelHandler = null
}
}

dispose() {
try {
this.removeParentCancelHandler()
}
finally {
this.removeAllListeners()
this._parent = null
}
}
}

export class CancellationError extends Error {
constructor() {
super("Cancelled")
}
}
29 changes: 18 additions & 11 deletions packages/electron-builder-http/src/httpExecutor.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { createHash } from "crypto"
import { Transform } from "stream"
import _debug from "debug"
import { EventEmitter } from "events"
import { createWriteStream } from "fs-extra-p"
import { RequestOptions } from "http"
import { parse as parseUrl } from "url"
import _debug from "debug"
import { ProgressCallbackTransform, ProgressInfo } from "./ProgressCallbackTransform"
import { safeLoad } from "js-yaml"
import { EventEmitter } from "events"
import { Socket } from "net"
import { Transform } from "stream"
import { parse as parseUrl } from "url"
import { CancellationToken } from "./CancellationToken"
import { ProgressCallbackTransform, ProgressInfo } from "./ProgressCallbackTransform"

export interface RequestHeaders {
[key: string]: any
@@ -149,7 +149,7 @@ export abstract class HttpExecutor<REQUEST_OPTS, REQUEST> {

protected abstract doRequest(options: any, callback: (response: any) => void): any

protected doDownload(requestOptions: any, destination: string, redirectCount: number, options: DownloadOptions, callback: (error: Error | null) => void) {
protected doDownload(requestOptions: any, destination: string, redirectCount: number, options: DownloadOptions, callback: (error: Error | null) => void, onCancel: (callback: () => void) => void) {
const request = this.doRequest(requestOptions, (response: Electron.IncomingMessage) => {
if (response.statusCode >= 400) {
callback(new Error(`Cannot download "${requestOptions.protocol || "https"}://${requestOptions.hostname}/${requestOptions.path}", status ${response.statusCode}: ${response.statusMessage}`))
@@ -164,18 +164,19 @@ export abstract class HttpExecutor<REQUEST_OPTS, REQUEST> {
hostname: parsedUrl.hostname,
path: parsedUrl.path,
port: parsedUrl.port == null ? undefined : parsedUrl.port
}), destination, redirectCount++, options, callback)
}), destination, redirectCount++, options, callback, onCancel)
}
else {
callback(new Error(`Too many redirects (> ${this.maxRedirects})`))
}
return
}

configurePipes(options, response, destination, callback)
configurePipes(options, response, destination, callback, options.cancellationToken)
})
this.addTimeOutHandler(request, callback)
request.on("error", callback)
onCancel(() => request.abort())
request.end()
}

@@ -240,7 +241,7 @@ function safeGetHeader(response: any, headerKey: string) {
}
}

function configurePipes(options: DownloadOptions, response: any, destination: string, callback: (error: Error | null) => void) {
function configurePipes(options: DownloadOptions, response: any, destination: string, callback: (error: Error | null) => void, cancellationToken: CancellationToken) {
if (!checkSha2(safeGetHeader(response, "X-Checksum-Sha2"), options.sha2, callback)) {
return
}
@@ -262,11 +263,17 @@ function configurePipes(options: DownloadOptions, response: any, destination: st

let lastStream = response
for (const stream of streams) {
stream.on("error", callback)
stream.on("error", (error: Error) => {
if (!cancellationToken.cancelled) {
callback(error)
}
})
lastStream = lastStream.pipe(stream)
}

fileOut.on("finish", () => (<any>fileOut.close)(callback))
fileOut.on("finish", () => {
(<any>fileOut.close)(callback)
})
}

export function configureRequestOptions(options: RequestOptions, token?: string | null, method?: "GET" | "DELETE" | "PUT"): RequestOptions {
4 changes: 2 additions & 2 deletions packages/electron-builder-publisher/package.json
Original file line number Diff line number Diff line change
@@ -11,9 +11,9 @@
"out"
],
"dependencies": {
"fs-extra-p": "^3.1.0",
"fs-extra-p": "^4.0.1",
"mime": "^1.3.4",
"bluebird-lst-c": "^1.0.6",
"bluebird-lst": "^1.0.1",
"electron-builder-http": "~0.0.0-semantic-release",
"electron-builder-util": "~0.0.0-semantic-release",
"chalk": "^1.1.3",
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import BluebirdPromise from "bluebird-lst-c"
import BluebirdPromise from "bluebird-lst"
import { configureRequestOptions, HttpError } from "electron-builder-http"
import { BintrayClient, Version } from "electron-builder-http/out/bintray"
import { BintrayOptions } from "electron-builder-http/out/publishOptions"
2 changes: 1 addition & 1 deletion packages/electron-builder-publisher/src/gitHubPublisher.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import BluebirdPromise from "bluebird-lst-c"
import BluebirdPromise from "bluebird-lst"
import { configureRequestOptions, HttpError } from "electron-builder-http"
import { GithubOptions } from "electron-builder-http/out/publishOptions"
import { debug, isEmptyOrSpaces } from "electron-builder-util"
4 changes: 2 additions & 2 deletions packages/electron-builder-squirrel-windows/package.json
Original file line number Diff line number Diff line change
@@ -13,8 +13,8 @@
"dependencies": {
"electron-builder-util": "~0.0.0-semantic-release",
"electron-builder-core": "~0.0.0-semantic-release",
"bluebird-lst-c": "^1.0.6",
"fs-extra-p": "^3.1.0",
"bluebird-lst": "^1.0.1",
"fs-extra-p": "^4.0.1",
"archiver": "^1.3.0"
},
"typings": "./out/electron-builder-squirrel-windows.d.ts"
12 changes: 6 additions & 6 deletions packages/electron-builder-squirrel-windows/src/squirrelPack.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import * as path from "path"
import BluebirdPromise from "bluebird-lst-c"
import { remove, copy, createWriteStream, unlink, ensureDir, stat } from "fs-extra-p"
import { spawn, exec, prepareArgs, execWine, debug } from "electron-builder-util"
import { WinPackager } from "electron-builder/out/winPackager"
import BluebirdPromise from "bluebird-lst"
import { debug, exec, execWine, prepareArgs, spawn } from "electron-builder-util"
import { copyFile, walk } from "electron-builder-util/out/fs"
import { log } from "electron-builder-util/out/log"
import { walk, copyFile } from "electron-builder-util/out/fs"
import { WinPackager } from "electron-builder/out/winPackager"
import { copy, createWriteStream, ensureDir, remove, stat, unlink } from "fs-extra-p"
import * as path from "path"

const archiver = require("archiver")

4 changes: 2 additions & 2 deletions packages/electron-builder-util/package.json
Original file line number Diff line number Diff line change
@@ -11,10 +11,10 @@
"out"
],
"dependencies": {
"fs-extra-p": "^3.1.0",
"fs-extra-p": "^4.0.1",
"is-ci": "^1.0.10",
"stat-mode": "^0.2.2",
"bluebird-lst-c": "^1.0.6",
"bluebird-lst": "^1.0.1",
"chalk": "^1.1.3",
"debug": "2.6.1",
"node-emoji": "^1.5.1",
8 changes: 4 additions & 4 deletions packages/electron-builder-util/src/binDownload.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { spawn, debug, debug7zArgs, getTempName, getCacheDirectory } from "./util"
import { rename, unlink, emptyDir } from "fs-extra-p"
import { path7za } from "7zip-bin"
import BluebirdPromise from "bluebird-lst"
import { CancellationToken } from "electron-builder-http/out/CancellationToken"
import { emptyDir, rename, unlink } from "fs-extra-p"
import * as path from "path"
import BluebirdPromise from "bluebird-lst-c"
import { statOrNull } from "./fs"
import { httpExecutor } from "./nodeHttpExecutor"
import { CancellationToken } from "electron-builder-http/out/CancellationToken"
import { debug, debug7zArgs, getCacheDirectory, getTempName, spawn } from "./util"

const versionToPromise = new Map<string, BluebirdPromise<string>>()

8 changes: 4 additions & 4 deletions packages/electron-builder-util/src/fs.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { unlink, access, stat, Stats, lstat, readdir, createReadStream, createWriteStream, link, mkdirs, readlink, symlink } from "fs-extra-p"
import BluebirdPromise from "bluebird-lst-c"
import * as path from "path"
import { debug } from "./util"
import BluebirdPromise from "bluebird-lst"
import { access, createReadStream, createWriteStream, link, lstat, mkdirs, readdir, readlink, stat, Stats, symlink, unlink } from "fs-extra-p"
import isCi from "is-ci"
import * as path from "path"
import Mode from "stat-mode"
import { debug } from "./util"

export const MAX_FILE_REQUESTS = 8
export const CONCURRENCY = {concurrency: MAX_FILE_REQUESTS}
Loading

0 comments on commit 91613a9

Please sign in to comment.