import { Transform } from "stream"
import { CancellationToken } from "./CancellationToken"
export interface ProgressInfo {
total: number
delta: number
transferred: number
percent: number
bytesPerSecond: number
}
export class ProgressCallbackTransform extends Transform {
private start = Date.now()
private transferred = 0
private delta = 0
private nextUpdate = this.start + 1000
constructor(
private readonly total: number,
private readonly cancellationToken: CancellationToken,
private readonly onProgress: (info: ProgressInfo) => any
) {
super()
}
_transform(chunk: any, encoding: string, callback: any) {
if (this.cancellationToken.cancelled) {
callback(new Error("cancelled"), null)
return
}
this.transferred += chunk.length
this.delta += chunk.length
const now = Date.now()
if (now >= this.nextUpdate && this.transferred !== this.total ) {
this.nextUpdate = now + 1000
this.onProgress({
total: this.total,
delta: this.delta,
transferred: this.transferred,
percent: (this.transferred / this.total) * 100,
bytesPerSecond: Math.round(this.transferred / ((now - this.start) / 1000)),
})
this.delta = 0
}
callback(null, chunk)
}
_flush(callback: any): void {
if (this.cancellationToken.cancelled) {
callback(new Error("cancelled"))
return
}
this.onProgress({
total: this.total,
delta: this.delta,
transferred: this.total,
percent: 100,
bytesPerSecond: Math.round(this.transferred / ((Date.now() - this.start) / 1000)),
})
this.delta = 0
callback(null)
}
}