import { Subject , Observable } from 'rxjs' ; import { IPC } from '../services/service.electron.ipc' ; import { CancelablePromise } from 'chipmunk.client.toolkit' ; import EventsHubService from '../services/standalone/service.eventshub' ; import ElectronIpcService from '../services/service.electron.ipc' ; import FileOpenerService from '../services/service.file.opener' ; import * as Toolkit from 'chipmunk.client.toolkit' ; import * as moment from 'moment' ; export interface IFile { lastModified : number ; lastModifiedDate : Date ; name : string ; path : string ; size : number ; type : string ; } export interface IConcatFile { parser : string | undefined ; path : string ; name : string ; size : number ; created : number ; changed : number ; createdStr : string ; changedStr : string ; selected : boolean ; request : string ; matches : number ; } export class ControllerFileConcatSession { private _logger : Toolkit . Logger ; private _session : string ; private _tasks : Map < string , CancelablePromise < any , any , any , any > > = new Map ( ) ; private _files : Map < string , IConcatFile > = new Map ( ) ; private _regexpstr : string = '' ; private _subjects : { FileUpdated : Subject < IConcatFile > ; FilesUpdated : Subject < IConcatFile [ ] > ; } = { FileUpdated : new Subject < IConcatFile > ( ) , FilesUpdated : new Subject < IConcatFile [ ] > ( ) , } ; constructor ( session ) { this . _session = session ; this . _logger = new Toolkit . Logger ( `ControllerFileConcatSession: ${ session }` ) ; } public destroy ( ) { return new Promise ( ( resolve , reject ) => { if ( this . _tasks . size === 0 ) { this . _logger . debug ( `No active tasks; no need to abort any.` ) ; return resolve ( ) ; } Promise . all ( Array . from ( this . _tasks . values ( ) ) . map ( ( task ) => { return new Promise ( ( resolveTask ) => { task . canceled ( resolveTask ) ; task . abort ( 'Controller is going to be destroyed' ) ; } ) ; } ) ) . then ( ( ) => { resolve ( ) ; this . _logger . debug ( `All tasks are aborted; controller is destroyed.` ) ; } ) . catch ( ( err ) => { this . _logger . error ( `Unexpected error during destroying: ${ err . message }` ) ; reject ( err ) ; } ) ; } ) ; } public getFiles ( ) { return Array . from ( this . _files . values ( ) ) ; } public getGuid ( ) { return this . _session ; } public getObservable ( ) { return { FileUpdated : this . _subjects . FileUpdated . asObservable ( ) , FilesUpdated : this . _subjects . FilesUpdated . asObservable ( ) , } ; } public add ( files ) { return new Promise ( ( resolve , reject ) => { FileOpenerService . getDetailedFileList ( files ) . then ( ( list ) => { Promise . all ( list . filter ( ( f ) => f . features . concat ) . map ( ( file ) => { return new Promise ( ( next ) => { this . _addFileByPath ( file . path ) . then ( ( ) => { const fileDesc = this . _files . get ( file . path ) ; fileDesc !== undefined && this . _subjects . FileUpdated . next ( fileDesc ) ; this . _subjects . FilesUpdated . next ( Array . from ( this . _files . values ( ) ) ) ; next ( undefined ) ; } ) . catch ( ( fileErr ) => { this . _logger . warn ( `Fail to get file info for "${ file . path }" due error: ${ fileErr . message }` ) ; next ( undefined ) ; } ) ; } ) ; } ) ) . then ( ( ) => { resolve ( ) ; } ) . catch ( ( error ) => { this . _logger . warn ( `Fail to get file info due error: ${ error . message }` ) ; reject ( error ) ; } ) ; } ) . catch ( reject ) ; } ) ; } public remove ( path ) { this . _files . delete ( path ) ; this . _subjects . FilesUpdated . next ( Array . from ( this . _files . values ( ) ) ) ; } public update ( path , file ) { if ( ! this . _files . has ( path ) ) { return false ; } this . _files . set ( path , file ) ; this . _subjects . FileUpdated . next ( file ) ; return true ; } public set ( files ) { this . _files . clear ( ) ; files . forEach ( ( file ) => { this . _files . set ( file . path , file ) ; } ) ; this . _subjects . FilesUpdated . next ( files ) ; return true ; } public getRegExpStr ( ) { return this . _regexpstr ; } public drop ( ) { this . _files . clear ( ) ; this . _regexpstr = '' ; this . _subjects . FilesUpdated . next ( [ ] ) ; } public concat ( ) { const id = Toolkit . guid ( ) ; const task = new CancelablePromise < void > ( ( resolve , reject ) => { EventsHubService . getSubject ( ) . onKeepScrollPrevent . next ( undefined ) ; ElectronIpcService . request < IPC . ConcatFilesResponse > ( new IPC . ConcatFilesRequest ( { files : Array . from ( this . _files . values ( ) ) . map ( ( file ) => { return { parser : file . parser , file : file . path , } ; } ) , id : Toolkit . guid ( ) , session : this . _session , } ) , IPC . ConcatFilesResponse ) . then ( ( response ) => { if ( typeof response . error === 'string' && response . error . trim ( ) !== '' ) { this . _logger . error ( `Concat operation was failed due error: ${ response . error }` ) ; return reject ( new Error ( response . error ) ) ; } resolve ( ) ; } ) . catch ( ( concatErr ) => { this . _logger . error ( `Fail to do concat due error: ${ concatErr . message }` ) ; reject ( concatErr ) ; } ) ; } ) . finally ( ( ) => { this . _tasks . delete ( id ) ; } ) ; this . _tasks . set ( id , task ) ; return task ; } public search ( regexpstr ) { const id = Toolkit . guid ( ) ; const task = new CancelablePromise < void > ( ( resolve , reject ) => { if ( regexpstr . trim ( ) === '' ) { return ; } if ( ! Toolkit . regTools . isRegStrValid ( regexpstr ) ) { return ; } ElectronIpcService . request < IPC . FilesSearchResponse > ( new IPC . FilesSearchRequest ( { files : Array . from ( this . _files . values ( ) ) . map ( ( file ) => { return file . path ; } ) , requests : [ { source : regexpstr , flags : 'gi' } ] , } ) , IPC . FilesSearchResponse ) . then ( ( response ) => { if ( typeof response . error === 'string' && response . error . trim ( ) !== '' ) { this . _logger . warn ( `Fail to search files due error: ${ response . error }` ) ; return reject ( new Error ( `Fail to search files due error: ${ response . error }` ) ) ; } if ( typeof response . matches !== 'object' || response . matches === null ) { this . _regexpstr = '' ; } else { this . _regexpstr = regexpstr ; this . _files . forEach ( ( file , key ) => { if ( response . matches [ file . path ] === undefined ) { file . matches = 0 ; file . request = '' ; } else { file . matches = response . matches [ file . path ] ; file . request = regexpstr ; } this . _files . set ( key , file ) ; this . _subjects . FileUpdated . next ( file ) ; } ) ; this . _subjects . FilesUpdated . next ( Array . from ( this . _files . values ( ) ) ) ; } resolve ( ) ; } ) . catch ( ( error ) => { this . _logger . warn ( `Fail to search files due error: ${ error . message }` ) ; reject ( error ) ; } ) ; } ) . finally ( ( ) => { this . _tasks . delete ( id ) ; } ) ; this . _tasks . set ( id , task ) ; return task ; } private _addFileByPath ( path ) { const id = Toolkit . guid ( ) ; const task = new CancelablePromise ( ( resolve , reject ) => { if ( this . _files . has ( path ) ) { return resolve ( ) ; } this . _getFileStats ( path ) . then ( ( stats ) => { this . _files . set ( path , { path : stats . path , name : stats . name , parser : stats . parser , size : stats . size , created : stats . created , changed : stats . changed , createdStr : moment ( stats . created ) . format ( 'DD/MM/YYYY hh:mm:ss.s' ) , changedStr : moment ( stats . changed ) . format ( 'DD/MM/YYYY hh:mm:ss.s' ) , selected : false , matches : 0 , request : '' , } ) ; resolve ( ) ; } ) . catch ( ( parserError ) => { reject ( new Error ( `Fail detect file parser due error: ${ parserError . message }` ) ) ; } ) ; } ) . finally ( ( ) => { this . _tasks . delete ( id ) ; } ) ; this . _tasks . set ( id , task ) ; return task ; } private _getFileStats ( file ) { const id = Toolkit . guid ( ) ; const task = new CancelablePromise < IPC . FileInfoResponse > ( ( resolve , reject ) => { ElectronIpcService . request < IPC . FileInfoResponse > ( new IPC . FileInfoRequest ( { file : file , } ) , IPC . FileInfoResponse ) . then ( ( stats ) => { if ( stats . parser === undefined ) { return reject ( new Error ( 'Fail to find parser for selected file.' ) ) ; } resolve ( stats ) ; } ) . catch ( ( error ) => { reject ( error ) ; } ) ; } ) . finally ( ( ) => { this . _tasks . delete ( id ) ; } ) ; this . _tasks . set ( id , task ) ; return task ; } }