node-file-handler.ts 2.13 KB
import { Observable } from 'rxjs/Observable';
import { Subscriber } from 'rxjs/Subscriber';
import { FileHandler } from '../api/file-handler';
import * as http from 'http';
import * as https from 'https';
import * as fs from 'fs';

export class NodeFileHandler 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) : Observable<number> {

        let handler = this.selectProtocol(source);

        return Observable.create((subscriber:Subscriber<number>) => {
            
            if (!handler) {
                subscriber.error("No handler for source: " + source);
                return;
            }

            // file already exists and is not empty
            if (fs.existsSync(target) && (fs.statSync(target)['size'] > 0)) {
                subscriber.complete();
                return;
            }

            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) {
                        subscriber.next(prog / size);
                        nextProg += (1 / progCounts);
                    }                
                });

                response.on('end', () => {
                    file.end();
                    subscriber.complete();
                });
            
            }).on('error', (error) => {
                fs.unlink(target);
                subscriber.error("Error while downloading: " + error);
            });

        });

    }

}