import Web3 from 'web3' ; import { Cargo } from './cargo' ; type EventCallback = ( ... args : any [ ] ) => void ; class Emitter { events : { [ eventName ] : EventCallback [ ] ; } ; constructor ( ) { this . events = { } ; } on ( name , fn ) { const event = this . events [ name ] ; if ( event ) { this . events [ name ] . push ( fn ) ; } else { this . events [ name ] = [ fn ] ; } } once ( name , fn ) { fn . __once__ = true ; this . on ( name , fn ) ; } emit ( name , ... args ) { const event = this . events [ name ] ; if ( Array . isArray ( event ) ) { event . forEach ( ( fn , i ) => { fn ( ... args ) ; if ( fn . __once__ ) { event . splice ( i , 1 ) ; } } ) ; } } } const getBlock = ( web3 , ... args ) : Promise < number > => new Promise ( resolve => { web3 . eth . getBlock ( ... args , ( err , block ) => { resolve ( err || ! block ? - 1 : block . number ) ; } ) ; } ) ; export default class PollTx extends Emitter { pending : string [ ] ; completed : string [ ] ; watching : boolean ; cargo : Cargo ; constructor ( cargo ) { super ( ) ; this . cargo = cargo ; this . pending = [ ] ; this . completed = [ ] ; this . watching = false ; } public watch ( tx ) { this . pending . push ( tx ) ; if ( ! this . watching ) { this . startWatching ( ) ; } this . emit ( 'pending' , tx , this . pending ) ; } private internalWatch = async ( ) => { if ( ! this . watching ) { return ; } const txData = await Promise . all ( this . pending . map ( tx => this . cargo . api . getTransaction ( tx ) ) ) ; const completed = txData . filter ( ( tx ) => ! ! tx && tx . blockNumber != null ) ; if ( completed . length > 0 ) { await Promise . all ( completed . map ( ( tx ) => ( async ( ) => { const { blockNumber } = tx ; let block ; try { block = await getBlock ( this . cargo . web3 , 'latest' ) ; } catch ( e ) { console . error ( e . message ) ; } if ( block && block - blockNumber >= 0 ) { this . completedFn ( tx ) ; } } ) ( ) ) ) ; } window . setTimeout ( this . internalWatch , 1000 ) ; } ; private startWatching ( ) { if ( this . watching ) return ; this . watching = true ; this . internalWatch ( ) ; } private completedFn ( tx ) { this . pending = this . pending . filter ( t => t !== tx . hash ) ; this . completed . push ( tx . hash ) ; this . emit ( 'completed' , tx . hash , this . pending ) ; if ( this . pending . length === 0 ) { this . watching = false ; } } }