import { SFTPWrapper } from 'ssh2' ; import BaseSSH2Promise from './BaseSSH2Promise' ; import SFTP from './sftp' ; import SSHConfig from "./sshConfig" ; import SSHConnection from './sshConnection' ; import SSHConstants from './sshConstants' ; import SSHUtils from './sshUtils' ; function isRegistered ( sshConnection , sshTunnel ) { return sshTunnel . deregister . filter ( ( i ) => { return i . sshConnection . config . uniqueId === sshConnection . config . uniqueId ; } ) . length > 0 ; } function register ( sshConnection , sshTunnel , isLast ) { var events = [ SSHConstants . CHANNEL . SSH , SSHConstants . CHANNEL . TUNNEL ] ; sshConnection . __sshTunnels = sshConnection . __sshTunnels || [ ] ; sshConnection . __sshTunnels . push ( sshTunnel ) ; var cbs = events . map ( ( event ) => { var cb = ( function ( ) { this . emit . apply ( this , arguments ) ; } ) . bind ( sshTunnel , event ) ; sshConnection . on ( event , cb ) ; return cb ; } ) ; var disconnectEvent = `${ SSHConstants . CHANNEL . SSH }:${ SSHConstants . STATUS . DISCONNECT }` ; var disconnectCb = ( ) => { var del ; for ( var i = 0 ; i < sshTunnel . config . length ; i ++ ) { if ( sshTunnel . config [ i ] . uniqueId === sshConnection . config . uniqueId ) { del = true ; } if ( del && SSH2Promise . __cache [ sshTunnel . config [ i ] . uniqueId ] ) { SSH2Promise . __cache [ sshTunnel . config [ i ] . uniqueId ] . close ( ) ; delete SSH2Promise . __cache [ sshTunnel . config [ i ] . uniqueId ] ; } } } ; events . push ( disconnectEvent ) ; cbs . push ( disconnectCb ) ; sshConnection . on ( disconnectEvent , disconnectCb ) ; return { sshConnection : sshConnection , events : events , close : function ( ) { var idx = sshConnection . __sshTunnels . indexOf ( sshTunnel ) ; sshConnection . __sshTunnels . splice ( idx , 1 ) ; if ( sshConnection . __sshTunnels . length > 0 ) { events . forEach ( ( event , idx ) => { sshConnection . removeListener ( event , cbs [ idx ] ) ; } ) ; return Promise . resolve ( ) ; } else { if ( sshConnection . config . sock ) { ( sshConnection . config . sock as any ) . destroy ( ) ; } return sshConnection . close ( ) . then ( ( ) => { events . forEach ( ( event , idx ) => { sshConnection . removeListener ( event , cbs [ idx ] ) ; } ) ; } ) ; } } } ; } var methods = [ 'exec' , 'spawn' , { 'rawSFTP' : 'sftp' } , 'shell' , 'subsys' , 'x11' , 'getSocksPort' , 'getTunnel' , 'addTunnel' , 'closeTunnel' ] ; var defaultOptions = { reconnect : true , port : 22 , reconnectTries : 10 , reconnectDelay : 5000 } ; class SSH2Promise extends BaseSSH2Promise { /**
 * For caching SSH Connection
 */ static __cache : any = { } ; static SSH = SSHConnection ; static Utils = SSHUtils ; static SFTP = SFTP ; static Constants = SSHConstants ; rawSFTP : ( ) => Promise < SFTPWrapper > ; config : Array < SSHConfig > ; deregister : Array < any > ; disableCache : boolean ; constructor ( options , disableCache ? ) { super ( ) ; options = Array . isArray ( options ) ? options : [ options ] ; this . config = options . map ( ( o ) => { o = Object . assign ( { } , defaultOptions , o ) ; o . uniqueId = o . uniqueId || `${ o . username }@${ o . host }:${ o . port }` ; return o ; } ) ; this . deregister = [ ] ; this . disableCache = disableCache || false ; methods . forEach ( ( m ) => { var k = typeof m == "string" ? m : Object . keys ( m ) [ 0 ] ; ( this as any ) [ k ] = function ( ) { var params = arguments ; return this . connect ( ) . then ( ( sshConnection ) => { return sshConnection [ typeof m == "string" ? m : m [ k ] ] . apply ( sshConnection , params ) ; } ) ; } . bind ( this ) ; } ) ; } /**
     * Get SFTP session, with promise and async/await
     */ sftp ( ) { return new SFTP ( this ) ; } emit ( event , ... args ) { var config = SSHUtils . peek ( this . config ) ; if ( config . debug ) { config . debug ( arguments ) ; } return super . emit . apply ( this , arguments ) ; } param { * } sshConfig getSSHConnection ( sshConfig , isLast ) { var ret ; if ( this . disableCache ) { ret = new SSHConnection ( sshConfig ) ; } else { if ( sshConfig && ! SSH2Promise . __cache [ sshConfig . uniqueId ] ) { ret = SSH2Promise . __cache [ sshConfig . uniqueId ] = new SSHConnection ( sshConfig ) ; } ret = SSH2Promise . __cache [ sshConfig . uniqueId ] ; } if ( ! isRegistered ( ret , this ) ) { this . deregister . push ( register ( ret , this , isLast ) ) ; } return ret . connect ( ) . then ( ( ssh ) => { ssh . emit ( SSHConstants . CHANNEL . SSH , SSHConstants . STATUS . CONNECT ) ; return ssh ; } ) ; } param { * } Single connect ( ) { var lastSSH ; for ( var i = 0 ; i < this . config . length ; i ++ ) { ( ( sshConfig , isLast ) => { if ( ! lastSSH ) { lastSSH = this . getSSHConnection ( sshConfig , isLast ) ; } else { lastSSH = lastSSH . then ( ( ssh ) => { if ( ssh . config . hoppingTool === SSHConstants . HOPPINGTOOL . SOCAT ) { return SSHUtils . checkStreamError ( ssh . spawn ( `socat - TCP:${ sshConfig . host }:${ sshConfig . port }` ) ) ; } else if ( ssh . config . hoppingTool === SSHConstants . HOPPINGTOOL . NATIVE ) { return ssh . forwardOut ( '127.0.0.1' , SSHUtils . getRandomPort ( ) , sshConfig . host , sshConfig . port ) ; } else { return SSHUtils . checkStreamError ( ssh . spawn ( `nc ${ sshConfig . host } ${ sshConfig . port }` ) ) ; } } ) . then ( ( stream ) => { sshConfig . sock = stream ; return this . getSSHConnection ( sshConfig , isLast ) ; } ) ; } } ) ( this . config [ i ] , i == this . config . length - 1 ) ; } return lastSSH ; } /**
     * Close SSH Connection
     */ close ( ) { return Promise . all ( this . deregister . map ( f => f . close ( ) ) ) ; } } export = SSH2Promise ;