Skip to content

Commit 1a3354a

Browse files
committed
feat: provide progress updates for multiple range differential downloads
1 parent e70da99 commit 1a3354a

File tree

3 files changed

+35
-4
lines changed

3 files changed

+35
-4
lines changed

packages/electron-updater/src/differentialDownloader/DataSplitter.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { newError } from "builder-util-runtime"
22
import { createReadStream } from "fs"
33
import { Writable } from "stream"
44
import { Operation, OperationKind } from "./downloadPlanBuilder"
5+
import { ProgressInfo } from "./ProgressDifferentialDownloadCallbackTransform"
56

67
const DOUBLE_CRLF = Buffer.from("\r\n\r\n")
78

@@ -34,6 +35,11 @@ export function copyData(task: Operation, out: Writable, oldFileFd: number, reje
3435
}
3536

3637
export class DataSplitter extends Writable {
38+
private start = Date.now()
39+
private nextUpdate = this.start + 1000
40+
private transferred = 0
41+
private delta = 0
42+
3743
partIndex = -1
3844

3945
private headerListBuffer: Buffer | null = null
@@ -49,7 +55,9 @@ export class DataSplitter extends Writable {
4955
private readonly partIndexToTaskIndex: Map<number, number>,
5056
boundary: string,
5157
private readonly partIndexToLength: Array<number>,
52-
private readonly finishHandler: () => any
58+
private readonly finishHandler: () => any,
59+
private readonly grandTotalBytes: number,
60+
private readonly onProgress?: (info: ProgressInfo) => any
5361
) {
5462
super()
5563

@@ -69,7 +77,27 @@ export class DataSplitter extends Writable {
6977
return
7078
}
7179

72-
this.handleData(data).then(callback).catch(callback)
80+
this.handleData(data)
81+
.then(() => {
82+
if (this.onProgress) {
83+
const now = Date.now()
84+
if (now >= this.nextUpdate || this.transferred === this.grandTotalBytes) {
85+
this.nextUpdate = now + 1000
86+
87+
this.onProgress({
88+
total: this.grandTotalBytes,
89+
delta: this.delta,
90+
transferred: this.transferred,
91+
percent: (this.transferred / this.grandTotalBytes) * 100,
92+
bytesPerSecond: Math.round(this.transferred / ((now - this.start) / 1000)),
93+
})
94+
this.delta = 0
95+
}
96+
}
97+
98+
callback()
99+
})
100+
.catch(callback)
73101
}
74102

75103
private async handleData(chunk: Buffer): Promise<undefined> {
@@ -217,6 +245,8 @@ export class DataSplitter extends Writable {
217245

218246
private processPartData(data: Buffer, start: number, end: number): Promise<void> {
219247
this.actualPartLength += end - start
248+
this.transferred += end - start
249+
this.delta += end - start
220250
const out = this.out
221251
if (out.write(start === 0 && data.length === end ? data : data.slice(start, end))) {
222252
return Promise.resolve()

packages/electron-updater/src/differentialDownloader/DifferentialDownloader.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,6 @@ export abstract class DifferentialDownloader {
132132
// Create our download info transformer if we have one
133133
let downloadInfoTransform: ProgressDifferentialDownloadCallbackTransform | undefined = undefined
134134
if (!this.options.isUseMultipleRangeRequest && this.options.onProgress) {
135-
// TODO: Does not support multiple ranges (someone feel free to PR this!)
136135
const expectedByteCounts: Array<number> = []
137136
let grandTotalBytes = 0
138137

packages/electron-updater/src/differentialDownloader/multipleRangeDownloader.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export function executeTasksUsingMultipleRangeRequests(
4141
function doExecuteTasks(differentialDownloader: DifferentialDownloader, options: PartListDataTask, out: Writable, resolve: () => void, reject: (error: Error) => void): void {
4242
let ranges = "bytes="
4343
let partCount = 0
44+
let grandTotalBytes = 0
4445
const partIndexToTaskIndex = new Map<number, number>()
4546
const partIndexToLength: Array<number> = []
4647
for (let i = options.start; i < options.end; i++) {
@@ -50,6 +51,7 @@ function doExecuteTasks(differentialDownloader: DifferentialDownloader, options:
5051
partIndexToTaskIndex.set(partCount, i)
5152
partCount++
5253
partIndexToLength.push(task.end - task.start)
54+
grandTotalBytes += task.end - task.start
5355
}
5456
}
5557

@@ -103,7 +105,7 @@ function doExecuteTasks(differentialDownloader: DifferentialDownloader, options:
103105
return
104106
}
105107

106-
const dicer = new DataSplitter(out, options, partIndexToTaskIndex, m[1] || m[2], partIndexToLength, resolve)
108+
const dicer = new DataSplitter(out, options, partIndexToTaskIndex, m[1] || m[2], partIndexToLength, resolve, grandTotalBytes, differentialDownloader.options.onProgress)
107109
dicer.on("error", reject)
108110
response.pipe(dicer)
109111

0 commit comments

Comments
 (0)