import ServiceElectron , { IPCMessages } from '../service.electron' ; import ServicePaths from '../service.paths' ; import Logger from '../../tools/env.logger' ; import { Subscription } from '../../tools/index' ; import { IService } from '../../interfaces/interface.service' ; import { spawn , ChildProcess } from 'child_process' ; import * as os from 'os' ; class description class ServiceFileSearch implements IService { private _logger : Logger = new Logger ( 'ServiceFileSearch' ) ; private _cmd : string = '' ; private _subscription : { [ key ] : Subscription ; } = { } ; returns public init ( ) { return new Promise ( ( resolve , reject ) => { this . _cmd = ServicePaths . getRG ( ) ; ServiceElectron . IPC . subscribe ( IPCMessages . FilesSearchRequest , this . _onFilesSearchRequest . bind ( this ) ) . then ( ( subscription ) => { this . _subscription . FilesSearchRequest = subscription ; resolve ( ) ; } ) . catch ( ( error ) => { this . _logger . error ( `Fail to init module due error: ${ error . message }` ) ; reject ( error ) ; } ) ; } ) ; } public destroy ( ) { return new Promise ( ( resolve ) => { Object . keys ( this . _subscription ) . forEach ( ( key ) => { this . _subscription [ key ] . destroy ( ) ; } ) ; resolve ( ) ; } ) ; } public getName ( ) { return 'ServiceFileSearch' ; } private _onFilesSearchRequest ( request , response ) { const req = request as IPCMessages . FilesSearchRequest ; this . _getMatchesCount ( req . files , req . requests . map ( ( r ) => { return new RegExp ( r . source , r . flags ) ; } ) ) . then ( ( matches ) => { response ( new IPCMessages . FilesSearchResponse ( { matches : matches , } ) ) ; } ) . catch ( ( error ) => { response ( new IPCMessages . FilesSearchResponse ( { matches : { } , error : error . message , } ) ) ; } ) ; } private _getMatchesCount ( files , regExp ) { return new Promise ( ( resolve , reject ) => { setImmediate ( ( ) => { if ( ! ( regExp instanceof Array ) ) { regExp = [ regExp ] ; } const args = [ '--count' , '--text' , '-i' , '-e' , `(${ regExp . map ( r => r . source ) . join ( '|' ) })` , ] ; args . push ( ... files ) ; let output = '' ; let errors = '' ; const process = spawn ( this . _cmd , args , { stdio : [ 'pipe' , 'pipe' , 'pipe' ] , } ) ; process . stdout ?. on ( 'data' , ( chunk ) => { if ( chunk instanceof Buffer ) { chunk = chunk . toString ( ) ; } if ( typeof chunk !== 'string' ) { return ; } output += chunk ; } ) ; process . stderr ?. on ( 'data' , ( chunk ) => { if ( chunk instanceof Buffer ) { chunk = chunk . toString ( ) ; } if ( typeof chunk !== 'string' ) { return ; } errors += chunk ; } ) ; process . once ( 'close' , ( ) => { if ( errors . trim ( ) !== '' ) { return reject ( new Error ( this . _logger . warn ( `Fail to make search due error: ${ errors }` ) ) ) ; } const results = { } ; output . split ( /[\n\r]/ ) . forEach ( ( result ) => { const parts = result . split ( ':' ) ; if ( os . platform ( ) === 'win32' && parts . length === 3 ) { parts [ 0 ] += ':' + parts [ 1 ] ; parts . splice ( 1 , 1 ) ; } if ( parts . length !== 2 ) { return this . _logger . warn ( `Fail to parser RG result line: ${ result }` ) ; } results [ parts [ 0 ] ] = parseInt ( parts [ 1 ] , 10 ) ; } ) ; resolve ( results ) ; } ) ; process . once ( 'error' , ( error ) => { this . _logger . error ( `Error during calling rg: ${ error . message }` ) ; reject ( error ) ; } ) ; } ) ; } ) ; } } export default ( new ServiceFileSearch ( ) ) ;