import * as fs from 'fs' ; import getGuid from '../../tools/tools.guid' ; import Logger from '../../tools/env.logger' ; export default class ControllerStreamFileReader { private _logger : Logger ; private _guid : string ; private _file : string ; private _streams : Map < string , fs . ReadStream > = new Map ( ) ; private _locked : boolean = false ; constructor ( guid , file ) { this . _guid = guid ; this . _file = file ; this . _logger = new Logger ( `ControllerStreamFileReader: ${ this . _guid }/${ this . _file }` ) ; } public destroy ( ) { this . _locked = true ; this . drop ( ) ; } public drop ( ) { this . _streams . forEach ( ( stream , guid ) => { this . _destroy ( guid , stream ) ; } ) ; } param from param to returns public read ( from , to ) { return new Promise ( ( resolve , reject ) => { if ( this . _locked ) { return reject ( new Error ( `Reader of stream is locked` ) ) ; } fs . stat ( this . _file , ( err , stat ) => { if ( err ) { return reject ( err ) ; } const options = { autoClose : true , encoding : 'utf8' } ; if ( to < 0 ) { return reject ( new Error ( this . _logger . error ( `Both parameters (from, to) cannot be < 0` ) ) ) ; } if ( from < 0 ) { options . start = stat . size - to ; options . end = stat . size - 1 ; } else if ( from >= 0 && to > 0 ) { options . start = from ; options . end = to ; } let output = '' ; const guid = getGuid ( ) ; const stream = fs . createReadStream ( this . _file , options ) ; stream . on ( 'data' , ( chunk ) => { output += chunk ; if ( stream !== undefined && stream . bytesRead >= ( options . end - options . start ) ) { this . _destroy ( guid , stream ) ; resolve ( output ) ; } } ) ; stream . on ( 'end' , ( ) => { this . _destroy ( guid , stream ) ; fs . stat ( this . _file , ( statErr , updatedStat ) => { if ( statErr ) { this . _logger . warn ( `Reader finished read data unexpectable. Requested: ${ options . start } - ${ options . end }. Fail get stat file information due error: ${ statErr . message }` ) ; } else { this . _logger . warn ( `Reader finished read data unexpectable. File size: ${ updatedStat . size } bytes. Requested: ${ options . start } - ${ options . end }` ) ; } resolve ( output ) ; } ) ; } ) ; this . _streams . set ( guid , stream ) ; } ) ; } ) ; } public _destroy ( guid , stream ) { stream . removeAllListeners ( ) ; stream . close ( ) ; stream . destroy ( ) ; this . _streams . delete ( guid ) ; } }