import * as path from 'path' ; import * as stream from 'stream' ; import * as tmp from 'tmp' ; import { succeeded , Errorable } from '../../errorable' ; import { Dictionary } from '../../utils/dictionary' ; import { sleep } from '../../sleep' ; type DownloadFunc = ( url : string , destination ? : string , options ? : any ) => Promise < Buffer > & stream . Duplex ; let download ; const DOWNLOAD_ONCE_STATUS = Dictionary . of < DownloadOperationStatus > ( ) ; enum DownloadOperationStatus { Queued = 1 , Completed = 2 , Failed = 3 } function ensureDownloadFunc ( ) { if ( ! download ) { const home = process . env [ 'HOME' ] ; download = require ( 'download' ) ; if ( home ) { process . env [ 'HOME' ] = home ; } } } export async function toTempFile ( sourceUrl ) { const tempFileObj = tmp . fileSync ( { prefix : "vsk-autoinstall-" } ) ; const downloadResult = await to ( sourceUrl , tempFileObj . name ) ; if ( succeeded ( downloadResult ) ) { return { succeeded : true , result : tempFileObj . name } ; } return { succeeded : false , error : downloadResult . error } ; } export async function to ( sourceUrl , destinationFile ) { ensureDownloadFunc ( ) ; try { await download ! ( sourceUrl , path . dirname ( destinationFile ) , { filename : path . basename ( destinationFile ) } ) ; return { succeeded : true , result : null } ; } catch ( e ) { return { succeeded : false , error : [ e . message ] } ; } } export async function once ( sourceUrl , destinationFile ) { const downloadStatus = DOWNLOAD_ONCE_STATUS [ destinationFile ] ; if ( ! downloadStatus || downloadStatus === DownloadOperationStatus . Failed ) { DOWNLOAD_ONCE_STATUS [ destinationFile ] = DownloadOperationStatus . Queued ; const result = await to ( sourceUrl , destinationFile ) ; DOWNLOAD_ONCE_STATUS [ destinationFile ] = succeeded ( result ) ? DownloadOperationStatus . Completed : DownloadOperationStatus . Failed ; return result ; } else { while ( true ) { await sleep ( 100 ) ; if ( DOWNLOAD_ONCE_STATUS [ destinationFile ] === DownloadOperationStatus . Completed ) { return { succeeded : true , result : null } ; } else { return await once ( sourceUrl , destinationFile ) ; } } } }