new Downloader

Posted acmeryblog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了new Downloader相关的知识,希望对你有一定的参考价值。

/**

  • Simple Node.js Download Client.
    • Only support http and https.
    • Only support get method.
      */

import * as path from "path";
import * as fs from "fs";
import { URL } from "url";
import * as http from "http";
import * as https from "https";

export interface IDownloaderItem {
src: URL;
dest: URL;
fileName?: string;
}

export class Downloader {

public downloadFile(item: IDownloaderItem): any {
    let error: Error | null | undefined;
    if (item.src.protocol === "http:") {
        return this.httpDownload(item);
    } else if (item.src.protocol === "https:") {
        return this.httpsDownload(item);
    } else {
        error = new Error(`Downloader is not support ${item.src.protocol.split(":")[0]} protocol!`);
    }
    if (!(error === null || error === undefined)) {
        console.error(error.message);
        return;
    }
}

private httpDownload(item: IDownloaderItem): any {
    let error: Error | null | undefined;
    let saveFilePath: string | null | undefined;
    http.get(item.src, (res) => {
        if (res.statusCode === 200) {
            saveFilePath = path.join(item.dest.pathname, this.getSaveFileName(item, res));
            let totalFileSize = this.getDownloadFileSize(res);
            console.log(`Starting download.
SavePath:${saveFilePath}. 
TotalSize: ${this.getHumanFileSize(totalFileSize)}. `);
            let writeStream = fs.createWriteStream(saveFilePath);
            res.pipe(writeStream);
            writeStream.on('close', () => {
                console.log('Finished download.');
                return saveFilePath;
            });
        } else if (res.statusCode === 302) {
            let location = res.headers['location'];
            console.log(`It's a redirect download: ${location}`);
            if (!(location === undefined)) {
                item.src = new URL(location);
            }
            this.downloadFile(item);
        } else {
            error = new Error('Request Failed. ' + `Status Code: ${res.statusCode}`);
        }
        if (!(error === null || error === undefined)) {
            console.error(error.message);
            res.resume();
            return;
        }
    });
}

private httpsDownload(item: IDownloaderItem): any {
    let error: Error | null | undefined;
    let saveFilePath: string | null | undefined;
    https.get(item.src, (res) => {
        if (res.statusCode === 200) {
            saveFilePath = path.join(item.dest.pathname, this.getSaveFileName(item, res));
            let totalFileSize = this.getDownloadFileSize(res);
            console.log(`Starting download.
SavePath:${saveFilePath}. 
TotalSize: ${this.getHumanFileSize(totalFileSize)}. `);
            fs.mkdirSync(item.dest.pathname, { recursive: true });
            let writeStream = fs.createWriteStream(saveFilePath);
            res.pipe(writeStream);
            writeStream.on('close', () => {
                console.log('Finished download.');
                return saveFilePath;
            });
        } else if (res.statusCode === 302) {
            let location = res.headers['location'];
            console.log(`It's a redirect download: ${location}`);
            if (!(location === undefined)) {
                item.src = new URL(location);
            }
            this.downloadFile(item);
        } else {
            error = new Error('Request Failed. ' + `Status Code: ${res.statusCode}`);
        }
        if (!(error === null || error === undefined)) {
            console.error(error.message);
            res.resume();
            return;
        }
    });
}

private getDownloadFileSize(res: http.IncomingMessage): number {
    let contentLength = res.headers['content-length'];
    if (contentLength === null || contentLength === undefined) {
        return 0;
    } else {
        return Number(contentLength);
    }
}

private getHumanFileSize(fileSize: number) {

    if (fileSize < 1024) {
        return `${fileSize} B`;
    } else if (fileSize < 1024 * 1024) {
        return `${(fileSize / (1024)).toFixed(2)} KB`;
    } else if (fileSize < 1024 * 1024 * 1024) {
        return `${(fileSize / (1024 * 1024)).toFixed(2)} MB`;
    } else if (fileSize < 1024 * 1024 * 1024 * 1024) {
        return `${(fileSize / (1024 * 1024 * 1024)).toFixed(2)} GB`;
    } else if (fileSize < 1024 * 1024 * 1024 * 1024 * 1024) {
        return `${(fileSize / (1024 * 1024 * 1024 * 1024)).toFixed(2)} TB`;
    } else {
        return `${fileSize} B`;
    }
}

private getSaveFileName(item: IDownloaderItem, res: http.IncomingMessage): string {
    if (!(item.fileName === null
        || item.fileName === undefined
        || item.fileName.trim().length === 0)) {
        return item.fileName.trim();
    }
    return this.getOriginalFileName(item, res);
}

private getOriginalFileName(item: IDownloaderItem, res: http.IncomingMessage): string {
    let fileName: string;
    // Get orgion filename by headers["content-disposition"].
    if (!(res.headers["content-disposition"] === null
        || res.headers["content-disposition"] === undefined
        || res.headers["content-disposition"].split("filename=").length === 1)) {
        fileName = res.headers["content-disposition"].split("filename=")[1].trim();
        if (fileName.length > 0) {
            return fileName;
        }
    }
    // Get orgion filename by url address.
    if (!(item.src.pathname === null
        || item.src.pathname === undefined
        || item.src.pathname.split("/").length === 1)) {
        fileName = item.src.pathname.split("/")[item.src.pathname.split("/").length - 1].trim();
        if (fileName.length > 0) {
            return fileName;
        }
    }
    // Get orgion filename by Date.
    let date = new Date();
    fileName = date.getFullYear().toString()
        + date.getMonth().toString()
        + date.getDay().toString()
        + date.getHours().toString()
        + date.getMinutes().toString()
        + date.getSeconds().toString()
        + date.getMilliseconds().toString()
        + ".tmp";
    return fileName;
}

}

以上是关于new Downloader的主要内容,如果未能解决你的问题,请参考以下文章

webMagic学习系列:downloader模块学习

这些 C++ 代码片段有啥作用?

P2P Downloader

YASnippet - emacs 的代码片段管理工具

渗透测试中的Node.js——Downloader的实现

爬虫日记(88):Scrapy的Downloader类