node-file-handler.ts 2.45 KB
import { Util } from './../util';
import { EventEmitter } from 'events';
import { FileHandler } from '../api/file-handler';
import { File } from '../api/file';
import * as http from 'http';
import * as https from 'https';
import * as fs from 'fs';

export class NodeFileHandler extends EventEmitter implements FileHandler {

    selectProtocol(url:string) : any {
        if (url.search(/^http:\/\//) === 0) {
            return http;
        } else if (url.search(/^https:\/\//) === 0) {
            return https;
        } else {
            return null;
        }
    }

    download(source:string, target:string) {

        let handler = this.selectProtocol(source);

        if (!handler) {
            this.emit("error","No handler for source: " + source);
            return this;
        }

        // file already exists and is not empty
        if (fs.existsSync(target) && (fs.statSync(target)['size'] > 0)) {
            this.emit("complete");
            return this;
        } else {
            let file = fs.createWriteStream(target, {'flags': 'a'});

            handler.get(source, (response) => {
                let size = response.headers['content-length']; // in bytes
                let prog = 0; // already downloaded
                let progCounts = 100; // how many progress events should be triggerd (1-100 %)
                let nextProg = (1/progCounts);
                
                response.on('data', (chunk) => {
                    prog += chunk.length;
                    file.write(chunk, 'binary');

                    if ((prog / size) > nextProg) {
                        this.emit('progress',prog / size);
                        nextProg += (1 / progCounts);
                    }                
                });

                response.once('end', () => {
                    file.end();
                    this.emit('complete');
                });            

            }).on('error', (error) => {
                fs.unlink(target);
                this.emit("error", "Error while downloading: " + error);
            });

            return this;
        }                
    }

    cleanup(files:Array<File>, basePath?:string) {
        try {
            let localFiles = fs.readdirSync(basePath);
            Util.getFilesForCleanup(files, localFiles)
                .forEach((file) => {
                    fs.unlinkSync(basePath + "/" + file);
                });           
        } catch (e) {
        }
    
        return this;
    }

}