Skip to content

Commit

Permalink
feat: browser-support (#1)
Browse files Browse the repository at this point in the history
* feat: browser-support
  • Loading branch information
ido-pluto authored Oct 31, 2023
1 parent 36cf2f0 commit c1616a0
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 48 deletions.
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ ipull set .zip ~/Downloads/zips
### NodeJS API

```ts
class PullProgress {
constructor(progress: IStreamProgress, onProgress: PullProgressCallback) {
}

startPull(): Promise<void> {
}
}

class CLIPullProgress {
constructor(progress: IStreamProgress, name: string) {
}
Expand Down Expand Up @@ -87,7 +95,7 @@ class CopyProgress implements IStreamProgress {
Example:

```ts
import {FastDownload} from 'ipull';
import {FastDownload, CLIPullProgress} from 'ipull';

const download = new FastDownload('http://example.com/file.txt', './file.txt');
await download.init();
Expand All @@ -96,6 +104,20 @@ const progress = new CLIPullProgress(download, 'file.txt');
await progress.startPull();
```

## Browser support
You can also use IPull without the CLI, just for download metadata

```ts
import PullProgress from 'ipull/pull-progress.js';

const pull = new PullProgress(download, (info) => {
console.log(info.speed);
});

pull.startPull();
```
- Make sure you import the exact file when using, so Node.js only modules will not be imported

## Credits

[Turbo-Downloader](https://www.npmjs.com/package/turbo-downloader) - The download engine used in this package
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
"LICENSE"
],
"exports": {
".": "./dist/index.js"
".": "./dist/index.js",
"./pull-progress": "./dist/download/pull-progress.js",
"./pull-progress.js": "./dist/download/pull-progress.js"
},
"engines": {
"node": ">=18.0.0"
Expand Down
58 changes: 12 additions & 46 deletions src/download/cli-pull-progress.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
import prettyBytes, {Options as PrettyBytesOptions} from "pretty-bytes";
import cliProgress from "cli-progress";
import chalk from "chalk";
import prettyMs, {Options as PrettyMsOptions} from "pretty-ms";
import {IStreamProgress} from "./stream-progress/istream-progress.js";
import PullProgress, {TransferProgressInfo} from "./pull-progress.js";

export default class CLIPullProgress {
private static readonly _PRETTY_MS_OPTIONS: PrettyMsOptions = {millisecondsDecimalDigits: 1, keepDecimalsOnWholeSeconds: true};
private static readonly _PRETTY_BYTES_OPTIONS: PrettyBytesOptions = {maximumFractionDigits: 2, minimumFractionDigits: 2};
private static readonly _AVERAGE_SPEED_LAST_SECONDS = 10;

private _speeds: { [dateInSeconds: number]: number } = [];
export default class CLIPullProgress extends PullProgress {
private _progressBar: cliProgress.SingleBar;
private _lastTransferred = 0;

public constructor(private _progress: IStreamProgress, private _name: string) {
public constructor( _progress: IStreamProgress, private _name: string) {
super(_progress, info => this._handleCLIUpdate(info));
this._progressBar = new cliProgress.SingleBar({
format: this._getProgressBarFormat(),
barCompleteChar: "\u2588",
Expand All @@ -22,59 +16,31 @@ export default class CLIPullProgress {
});
}

private static _formatSpeed(speed: number): string {
return prettyBytes(Math.min(speed, 9999999999) || 0, CLIPullProgress._PRETTY_BYTES_OPTIONS) + "/s";
}

private _calculateSpeed(currentTransferred: number): number {
const dateInSeconds = Math.floor(Date.now() / 1000);
this._speeds[dateInSeconds] ??= 0;
this._speeds[dateInSeconds] += currentTransferred - this._lastTransferred;
this._lastTransferred = currentTransferred;

let averageSecondsAverageSpeed = 0;
for (let i = 0; i < CLIPullProgress._AVERAGE_SPEED_LAST_SECONDS; i++) {
averageSecondsAverageSpeed += this._speeds[dateInSeconds - i] || 0;
}

for (const key in this._speeds) {
if (parseInt(key) < dateInSeconds - CLIPullProgress._AVERAGE_SPEED_LAST_SECONDS) {
delete this._speeds[key];
}
}

return averageSecondsAverageSpeed / CLIPullProgress._AVERAGE_SPEED_LAST_SECONDS;
}

private _handleProgress(transferred: number, total: number) {
private _handleCLIUpdate({total, transferred, speed, percentage, timeLeft, transferredBytes, ended}: TransferProgressInfo) {
this._progressBar.setTotal(total);

const speed = this._calculateSpeed(transferred);
const timeLeft = (total - transferred) / speed;
const percentage = ((transferred / total) * 100).toFixed(2);

this._progressBar.update(transferred, {
speed: CLIPullProgress._formatSpeed(speed),
percentage: percentage,
timeLeft: prettyMs((timeLeft || 0) * 1000, CLIPullProgress._PRETTY_MS_OPTIONS),
transferredBytes: `${prettyBytes(transferred, CLIPullProgress._PRETTY_BYTES_OPTIONS)}/${prettyBytes(total, CLIPullProgress._PRETTY_BYTES_OPTIONS)}`
speed,
percentage,
timeLeft,
transferredBytes
});

if (percentage === "100") {
if (ended) {
this._progressBar.stop();
console.log("\nConnecting transferred chunks, please wait...");
}
}

public async startPull(): Promise<void> {
public override async startPull(): Promise<void> {
this._progressBar.start(Infinity, 0, {
speed: "N/A",
percentage: 0,
timeLeft: "N/A",
transferredBytes: "0 bytes/0 bytes"
});

await this._progress.progress(this._handleProgress.bind(this));
await super.startPull();
console.log();
}

Expand Down
75 changes: 75 additions & 0 deletions src/download/pull-progress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import prettyBytes, {Options as PrettyBytesOptions} from "pretty-bytes";
import prettyMs, {Options as PrettyMsOptions} from "pretty-ms";
import {IStreamProgress} from "./stream-progress/istream-progress.js";
export {IStreamProgress};

export type TransferProgressInfo = {
transferred: number,
total: number,
speed: string,
percentage: string,
timeLeft: string,
transferredBytes: string,
ended: boolean
};

export type PullProgressCallback = (info: TransferProgressInfo) => void;

export default class PullProgress {
protected static readonly _PRETTY_MS_OPTIONS: PrettyMsOptions = {millisecondsDecimalDigits: 1, keepDecimalsOnWholeSeconds: true};
protected static readonly _PRETTY_BYTES_OPTIONS: PrettyBytesOptions = {maximumFractionDigits: 2, minimumFractionDigits: 2};
protected static readonly _AVERAGE_SPEED_LAST_SECONDS = 10;

private _speeds: { [dateInSeconds: number]: number } = [];
private _lastTransferred = 0;

public constructor(protected _progress: IStreamProgress, protected _onProgress: PullProgressCallback) {
}

private static _formatSpeed(speed: number): string {
return prettyBytes(Math.min(speed, 9999999999) || 0, PullProgress._PRETTY_BYTES_OPTIONS) + "/s";
}

private _calculateSpeed(currentTransferred: number): number {
const dateInSeconds = Math.floor(Date.now() / 1000);
this._speeds[dateInSeconds] ??= 0;
this._speeds[dateInSeconds] += currentTransferred - this._lastTransferred;
this._lastTransferred = currentTransferred;

let averageSecondsAverageSpeed = 0;
for (let i = 0; i < PullProgress._AVERAGE_SPEED_LAST_SECONDS; i++) {
averageSecondsAverageSpeed += this._speeds[dateInSeconds - i] || 0;
}

for (const key in this._speeds) {
if (parseInt(key) < dateInSeconds - PullProgress._AVERAGE_SPEED_LAST_SECONDS) {
delete this._speeds[key];
}
}

return averageSecondsAverageSpeed / PullProgress._AVERAGE_SPEED_LAST_SECONDS;
}

private _handleProgress(transferred: number, total: number) {
const speed = this._calculateSpeed(transferred);
const timeLeft = (total - transferred) / speed;
const percentage = ((transferred / total) * 100).toFixed(2);

const timeLeftPretty = prettyMs((timeLeft || 0) * 1000, PullProgress._PRETTY_MS_OPTIONS);
const transferredBytes = `${prettyBytes(transferred, PullProgress._PRETTY_BYTES_OPTIONS)}/${prettyBytes(total, PullProgress._PRETTY_BYTES_OPTIONS)}`;

Check warning on line 59 in src/download/pull-progress.ts

View workflow job for this annotation

GitHub Actions / test

This line has a length of 157. Maximum allowed is 140

this._onProgress({
transferred,
total,
speed: PullProgress._formatSpeed(speed),
percentage,
timeLeft: timeLeftPretty,
transferredBytes,
ended: percentage === "100"
});
}

public async startPull(): Promise<void> {
await this._progress.progress(this._handleProgress.bind(this));
}
}
7 changes: 7 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,19 @@ import {truncateText} from "./utils/truncate-text.js";
import CopyProgress from "./download/stream-progress/copy-progress.js";
import FastDownload from "./download/stream-progress/fast-download.js";
import {IStreamProgress} from "./download/stream-progress/istream-progress.js";
import PullProgress, {PullProgressCallback, TransferProgressInfo} from "./download/pull-progress.js";

export {
pullFileCLI,
CLIPullProgress,
PullProgress,
truncateText,
CopyProgress,
FastDownload,
IStreamProgress
};

export type {
TransferProgressInfo,
PullProgressCallback
};

0 comments on commit c1616a0

Please sign in to comment.