/********************************************************************************
 * Copyright (C) 2018 Red Hat, Inc. and others.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the Eclipse
 * Public License v. 2.0 are satisfied: GNU General Public License, version 2
 * with the GNU Classpath Exception which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 ********************************************************************************/ import { Emitter } from '@theia/core/lib/common/event' ; import { RPCProtocolImpl , MessageType , ConnectionClosedError } from '../../common/rpc-protocol' ; import { PluginHostRPC } from './plugin-host-rpc' ; import { reviver } from '../../plugin/types-impl' ; console . log ( 'PLUGIN_HOST(' + process . pid + ') starting instance' ) ; process . exit = function ( code ? ) : void { const err = new Error ( 'An plugin call process.exit() and it was prevented.' ) ; console . warn ( err . stack ) ; } as ( code ? : number ) => never ; const proc = process as any ; if ( proc . crash ) { proc . crash = function ( ) : void { const err = new Error ( 'An plugin call process.crash() and it was prevented.' ) ; console . warn ( err . stack ) ; } ; } process . on ( 'uncaughtException' , ( err ) => { console . error ( err ) ; } ) ; const unhandledPromises = [ ] ; process . on ( 'unhandledRejection' , ( reason , promise ) => { unhandledPromises . push ( promise ) ; setTimeout ( ( ) => { const index = unhandledPromises . indexOf ( promise ) ; if ( index >= 0 ) { promise . catch ( err => { unhandledPromises . splice ( index , 1 ) ; if ( terminating && ( ConnectionClosedError . is ( err ) || ConnectionClosedError . is ( reason ) ) ) { return ; } console . error ( `Promise rejection not handled in one second: ${ err } , reason: ${ reason }` ) ; if ( err && err . stack ) { console . error ( `With stack trace: ${ err . stack }` ) ; } } ) ; } } , 1000 ) ; } ) ; process . on ( 'rejectionHandled' , ( promise ) => { const index = unhandledPromises . indexOf ( promise ) ; if ( index >= 0 ) { unhandledPromises . splice ( index , 1 ) ; } } ) ; let terminating = false ; const emitter = new Emitter < string > ( ) ; const rpc = new RPCProtocolImpl ( { onMessage : emitter . event , send : ( m ) => { if ( process . send && ! terminating ) { process . send ( m ) ; } } } , { reviver : reviver } ) ; process . on ( 'message' , async ( message ) => { if ( terminating ) { return ; } try { const msg = JSON . parse ( message ) ; if ( 'type' in msg && msg . type === MessageType . Terminate ) { terminating = true ; emitter . dispose ( ) ; if ( 'stopTimeout' in msg && typeof msg . stopTimeout === 'number' && msg . stopTimeout ) { await Promise . race ( [ pluginHostRPC . terminate ( ) , new Promise ( resolve => setTimeout ( resolve , msg . stopTimeout ) ) ] ) ; } else { await pluginHostRPC . terminate ( ) ; } rpc . dispose ( ) ; if ( process . send ) { process . send ( JSON . stringify ( { type : MessageType . Terminated } ) ) ; } } else { emitter . fire ( message ) ; } } catch ( e ) { console . error ( e ) ; } } ) ; const pluginHostRPC = new PluginHostRPC ( rpc ) ; pluginHostRPC . initialize ( ) ;