import { Subscription } from '../../tools/index' ; import { IService } from '../../interfaces/interface.service' ; import { DLTConnectionController , IConnectionOptions , } from '../../controllers/connections/dlt.connection' ; import { dialog , SaveDialogReturnValue } from 'electron' ; import { CommonInterfaces } from '../../interfaces/interface.common' ; import { CExportSelectionActionId , CExportAllActionId } from '../../consts/output.actions' ; import ServiceStreams from '../service.streams' ; import Logger from '../../tools/env.logger' ; import ServiceStorage , { IStorageScheme } from '../service.storage' ; import ServiceElectron , { IPCMessages } from '../service.electron' ; import ServiceOutputExport from '../output/service.output.export' ; import indexer , { Progress , DLT , CancelablePromise } from 'indexer-neon' ; import * as Tools from '../../tools/index' ; class description class ServiceDLTDeamonConnector implements IService { private _logger : Logger = new Logger ( 'ServiceDLTDeamonConnector' ) ; private _subscriptions : { [ key ] : Subscription ; } = { } ; private _connections : Map < string , DLTConnectionController > = new Map ( ) ; private _connectionsHistory : string [ ] = [ ] ; private _saver : CancelablePromise < void , void , DLT . TDLTSocketEvents , DLT . TDLTSocketEventObject > | undefined ; returns public init ( ) { return new Promise ( ( resolve , reject ) => { this . _subscriptions . onSessionClosed = ServiceStreams . getSubjects ( ) . onSessionClosed . subscribe ( this . _onSessionClosed . bind ( this ) ) ; Promise . all ( [ ServiceElectron . IPC . subscribe ( IPCMessages . DLTDeamonConnectRequest , this . _onDLTDeamonConnectRequest . bind ( this ) ) . then ( ( subscription ) => { this . _subscriptions . DLTDeamonConnectRequest = subscription ; } ) , ServiceElectron . IPC . subscribe ( IPCMessages . DLTDeamonDisconnectRequest , this . _onDLTDeamonDisconnectRequest . bind ( this ) ) . then ( ( subscription ) => { this . _subscriptions . DLTDeamonDisconnectRequest = subscription ; } ) , ServiceElectron . IPC . subscribe ( IPCMessages . DLTDeamonRecentRequest , this . _onDLTDeamonRecentRequest . bind ( this ) ) . then ( ( subscription ) => { this . _subscriptions . DLTDeamonRecentRequest = subscription ; } ) , ServiceElectron . IPC . subscribe ( IPCMessages . DLTDeamonRecentDropRequest , this . _onDLTDeamonRecentDropRequest . bind ( this ) ) . then ( ( subscription ) => { this . _subscriptions . DLTDeamonRecentDropRequest = subscription ; } ) , ServiceElectron . IPC . subscribe ( IPCMessages . DLTDeamonSaveRequest , this . _onDLTDeamonSaveRequest . bind ( this ) ) . then ( ( subscription ) => { this . _subscriptions . DLTDeamonSaveRequest = subscription ; } ) , ] ) . then ( ( ) => { 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 . _subscriptions ) . forEach ( ( key ) => { this . _subscriptions [ key ] . destroy ( ) ; } ) ; Promise . all ( Array . from ( this . _connections . values ( ) ) . map ( ( connection ) => { return connection . destroy ( ) ; } ) ) . then ( ( ) => { resolve ( ) ; } ) . catch ( ( error ) => { this . _logger . error ( `Fail to correctly disconnect all due error: ${ error . message }` ) ; resolve ( ) ; } ) ; } ) ; } public getName ( ) { return 'ServiceDLTDeamonConnector' ; } public saveAs ( target , type , sections = [ ] ) { return new Promise ( ( resolve , reject ) => { this . getFileName ( ) . then ( ( filename ) => { if ( filename === undefined ) { return resolve ( undefined ) ; } this . _logger . info ( `Saving` ) ; this . _saver = indexer . exportDltFile ( target , type , filename , { sections : sections } ) . then ( ( ) => { this . _logger . info ( `Saved` ) ; resolve ( filename ) ; } ) . canceled ( ( ) => { this . _logger . info ( `Saving was canceled` ) ; resolve ( undefined ) ; } ) . catch ( ( error ) => { this . _logger . warn ( `Exception during saving: ${ error . message }` ) ; reject ( error ) ; } ) . finally ( ( ) => { this . _saver = undefined ; } ) . on ( 'progress' , ( event ) => { } ) ; } ) . catch ( ( error ) => { reject ( error ) ; } ) ; } ) ; } public getFileName ( ) { return new Promise ( ( resolve , reject ) => { const win = ServiceElectron . getBrowserWindow ( ) ; if ( win === undefined ) { return ; } dialog . showSaveDialog ( win , { title : 'Saving DLT stream' , filters : [ { name : 'DLT Files' , extensions : [ 'dlt' ] , } , ] , } ) . then ( ( returnValue ) => { resolve ( returnValue . filePath ) ; } ) . catch ( ( error ) => { this . _logger . error ( `Fail get filename for saving due error: ${ error . message }` ) ; reject ( error ) ; } ) ; } ) ; } private _onDLTDeamonConnectRequest ( request , response ) { const req = request as IPCMessages . DLTDeamonConnectRequest ; if ( this . _connections . has ( req . session ) ) { return response ( new IPCMessages . DLTDeamonConnectResponse ( { id : req . id , session : req . session , error : `Fail to create new connection, because connection already exists for session "${ req . session }"` , } ) ) ; } const options = { ecu : req . ecu , bindingAddress : req . bindingAddress , bindingPort : req . bindingPort , multicast : req . multicast , fibex : req . fibex , target : req . target , timezone : req . timezone , } ; const connection = new DLTConnectionController ( req . id , req . session , options ) ; const state = { connected : false , error : false , } ; connection . connect ( ) . then ( ( ) => { this . _connections . set ( req . session , connection ) ; connection . once ( DLTConnectionController . Events . connect , ( ) => { if ( state . error ) { return ; } if ( this . _connectionsHistory . indexOf ( req . session ) === - 1 ) { this . _connectionsHistory . push ( req . session ) ; ServiceOutputExport . setAction ( req . session , { id : CExportAllActionId , caption : 'Export all' , handler : this . _exportAll . bind ( this , req . session ) , isEnabled : this . _isExportPossible . bind ( this , req . session ) , source : IPCMessages . EOutputExportFeaturesSource . output , } ) ; ServiceOutputExport . setAction ( req . session , { id : CExportSelectionActionId , caption : 'Export selection' , handler : this . _exportSelection . bind ( this , req . session ) , isEnabled : this . _isExportPossible . bind ( this , req . session ) , source : IPCMessages . EOutputExportFeaturesSource . all , } ) ; } response ( new IPCMessages . DLTDeamonConnectResponse ( { id : req . id , session : req . session , } ) ) ; ServiceElectron . IPC . send ( new IPCMessages . DLTDeamonConnectEvent ( { id : req . id , session : req . session , } ) ) . catch ( ( error ) => { this . _logger . warn ( `Fail to notify front-end about connection due error: ${ error . message }` ) ; } ) ; this . _updateRecent ( options ) ; this . _logger . info ( `connected` ) ; state . connected = true ; } ) ; connection . once ( DLTConnectionController . Events . disconnect , ( ) => { if ( ! state . connected ) { response ( new IPCMessages . DLTDeamonConnectResponse ( { id : req . id , session : req . session , error : `Fail to connect` , } ) ) ; } this . _logger . info ( `disconnected` ) ; connection . removeAllListeners ( ) ; this . _connections . delete ( req . session ) ; ServiceElectron . IPC . send ( new IPCMessages . DLTDeamonDisconnectEvent ( { id : req . id , session : req . session , } ) ) . catch ( ( error ) => { this . _logger . warn ( `Fail to notify front-end about disconnection due error: ${ error . message }` ) ; } ) ; } ) ; connection . once ( DLTConnectionController . Events . error , ( error ) => { if ( ! state . connected ) { response ( new IPCMessages . DLTDeamonConnectResponse ( { id : req . id , session : req . session , error : `Fail to connect due error: ${ error . message }` , } ) ) ; } else { } this . _logger . warn ( `error: ${ error . message }` ) ; state . error = true ; } ) ; } ) . catch ( ( connectingError ) => { response ( new IPCMessages . DLTDeamonConnectResponse ( { id : req . id , session : req . session , error : `Fail to create new connection due error: ${ connectingError . message }` , } ) ) ; } ) ; } private _onDLTDeamonDisconnectRequest ( request , response ) { const req = request as IPCMessages . DLTDeamonDisconnectRequest ; const connection = this . _connections . get ( req . session ) ; if ( connection === undefined ) { return response ( new IPCMessages . DLTDeamonConnectResponse ( { id : req . id , session : req . session , error : `Fail to disconnect, because it wasn't connected or already was disconnected` , } ) ) ; } connection . destroy ( ) . then ( ( ) => { connection . removeAllListeners ( ) ; this . _connections . delete ( req . session ) ; ServiceElectron . IPC . send ( new IPCMessages . DLTDeamonDisconnectEvent ( { id : req . id , session : req . session , } ) ) . catch ( ( error ) => { this . _logger . warn ( `Fail to notify front-end about disconnection due error: ${ error . message }` ) ; } ) ; return response ( new IPCMessages . DLTDeamonConnectResponse ( { id : req . id , session : req . session , } ) ) ; } ) . catch ( ( error ) => { response ( new IPCMessages . DLTDeamonConnectResponse ( { id : req . id , session : req . session , error : `Fail to remove connection due error: ${ error . message }` , } ) ) ; } ) ; } private _onDLTDeamonRecentRequest ( request , response ) { const stored = ServiceStorage . get ( ) . get ( ) . recentDLTConnectorSettings ; response ( new IPCMessages . DLTDeamonRecentResponse ( { recent : stored instanceof Array ? stored : [ ] , } ) ) ; } private _onDLTDeamonRecentDropRequest ( request , response ) { ServiceStorage . get ( ) . set ( { recentDLTConnectorSettings : [ ] , } ) . catch ( ( err ) => { this . _logger . error ( err . message ) ; } ) ; response ( new IPCMessages . DLTDeamonRecentDropResponse ( ) ) ; } private _onDLTDeamonSaveRequest ( request , response ) { const req = request as IPCMessages . DLTDeamonSaveRequest ; if ( this . _connectionsHistory . indexOf ( req . session ) === - 1 ) { return response ( new IPCMessages . DLTDeamonSaveResponse ( { session : req . session , error : `Fail to find connection for session "${ req . session }"` , } ) ) ; } this . saveAs ( req . session , 'session' ) . then ( ( filename ) => { response ( new IPCMessages . DLTDeamonSaveResponse ( { session : req . session , filename : filename , } ) ) ; } ) . catch ( ( error ) => { this . _logger . error ( `Fail to save DLT Stream due error: ${ error . message }` ) ; response ( new IPCMessages . DLTDeamonSaveResponse ( { session : req . session , error : error . message , } ) ) ; } ) ; } private _onSessionClosed ( guid ) { const connection = this . _connections . get ( guid ) ; if ( connection === undefined ) { return ; } connection . destroy ( ) . then ( ( ) => { this . _connections . delete ( guid ) ; } ) . catch ( ( error ) => { this . _logger . error ( `Fail to disconnect in scope of the session "${ guid }" due error: ${ error . message }` ) ; } ) ; } private _updateRecent ( settings ) { let stored = ServiceStorage . get ( ) . get ( ) . recentDLTConnectorSettings ; let updated ; stored = stored . filter ( ( recent ) => { if ( recent . ecu === settings . ecu ) { return false ; } return true ; } ) ; if ( updated === undefined ) { updated = settings ; } stored . unshift ( updated ) ; ServiceStorage . get ( ) . set ( { recentDLTConnectorSettings : stored , } ) . catch ( ( err ) => { this . _logger . error ( err . message ) ; } ) ; } private _exportSelection ( session , request ) { return new Promise ( ( resolve , reject ) => { const sections = request . selection . map ( ( range ) => { return { first_line : range . from , last_line : range . to } ; } ) ; this . saveAs ( session , 'session' , sections ) . then ( ( ) => { resolve ( ) ; } ) . catch ( ( saveErr ) => { this . _logger . warn ( `Fail to save stream data due error: ${ saveErr . message }` ) ; reject ( saveErr ) ; } ) ; } ) ; } private _exportAll ( session ) { return new Promise ( ( resolve , reject ) => { this . saveAs ( session , 'session' ) . then ( ( ) => { resolve ( ) ; } ) . catch ( ( saveErr ) => { this . _logger . warn ( `Fail to save stream data due error: ${ saveErr . message }` ) ; reject ( saveErr ) ; } ) ; } ) ; } private _isExportPossible ( session , request ) { if ( this . _connections . has ( session ) ) { return false ; } return true ; } } export default new ServiceDLTDeamonConnector ( ) ;