/* Copyright IBM Corp. 2018 */ import { createWriteStream } from 'graceful-fs'; import { join, normalize, parse } from 'path'; import * as request from 'request'; import { defer, fromEvent, Observable, of } from 'rxjs'; import { filter, first, mapTo, mergeMap, takeUntil, tap } from 'rxjs/operators'; import { Entry, Parse } from 'unzip'; import { rxMkdirp } from './rx.walk'; const random_ua = require('random-ua'); function _skipPrefix(aName: string, aCount: number): string | null { // current name let idx = 0; for (let i = 0; i < aCount; ++i) { // find the next separator const nextIdx = aName.indexOf('/', idx); if (nextIdx >= idx) { idx = nextIdx + 1; } else { return null; } } // split return aName.substring(idx); } function _rxExtractEntry(aEntry: Entry, aDstDir: string, aSkip: number): Observable { // skip the prefix const path = _skipPrefix(aEntry.path, aSkip); if (!path) { // nothing return of('').pipe( tap(() => aEntry.autodrain()), filter(() => false) ); } // create filename const fileName = normalize(join(aDstDir, path)); // handle directories if (aEntry.type === 'Directory') { // create the directory return rxMkdirp(fileName).pipe( tap(() => aEntry.autodrain()), filter(() => false) ); } else { // parent path const parsedFileName = parse(fileName); const dirName = parsedFileName.dir; // create later return rxMkdirp(dirName).pipe( mergeMap(() => { // construct the stream const stream: any = aEntry.pipe(createWriteStream(fileName)); // attach return fromEvent(stream, 'close').pipe(first()); }), // map to the target name mapTo(fileName) ); } } function _rxUnzipFromUrl(aSrcUrl: string, aDstDir: string, aSkip: number = 0): Observable { // the options const options = { url: aSrcUrl, headers: { 'User-Agent': random_ua.generate() } }; // defer return defer(() => { // construct the stream const stream = request(options).pipe(Parse()); // handle const onEntry = fromEvent(stream, 'entry'); const onClose = fromEvent(stream, 'close'); // return the full stream return onEntry.pipe( takeUntil(onClose), mergeMap(entry => _rxExtractEntry(entry, aDstDir, aSkip)) ); }); } export { _rxUnzipFromUrl as rxUnzipFromUrl };