import TasitProviderHelpers from "@tasit/provider-helpers" ; const { ConfigLoader } = TasitProviderHelpers ; interface CustomError extends Error { eventName ? : any ; } export class Subscription { private ethersEventEmitter : any ; private eventListeners = new Map ( ) ; private timeout : any ; constructor ( eventEmitter ) { const { events } = ConfigLoader . getConfig ( ) ; const { timeout } = events ; this . timeout = timeout ; this . ethersEventEmitter = eventEmitter ; } _toEthersEventName = ( eventName ) => { if ( eventName === "confirmation" ) return "block" ; return eventName ; } ; off = ( eventName ) => { const eventListener = this . eventListeners . get ( eventName ) ; if ( ! eventListener ) { console . warn ( `A listener for event '${ eventName }' isn't registered.` ) ; return ; } if ( eventName !== "error" ) { this . _clearEventTimerIfExists ( eventName ) ; this . ethersEventEmitter . removeAllListeners ( this . _toEthersEventName ( eventName ) ) ; } this . eventListeners . delete ( eventName ) ; } ; getTimeout = ( ) => { return this . timeout ; } ; setTimeout = ( timeout ) => { this . timeout = timeout ; } ; _clearEventTimerIfExists = ( eventName ) => { const eventListener = this . eventListeners . get ( eventName ) ; if ( ! eventListener ) { console . warn ( `A listener for event '${ eventName }' isn't registered.` ) ; return ; } const { timer } = eventListener ; if ( ! timer ) return ; clearTimeout ( timer ) ; } ; unsubscribe = ( ) => { this . eventListeners . forEach ( ( _eventListener , eventName ) => { this . off ( eventName ) ; } ) ; } ; subscribedEventNames = ( ) => { return Array . from ( this . eventListeners . keys ( ) ) ; } ; _emitErrorEvent = ( error ) => { const errorEventListener = this . eventListeners . get ( "error" ) ; if ( ! errorEventListener ) { console . warn ( `Error emission without listener: ${ error }` ) ; return ; } errorEventListener . listener ( error ) ; } ; _emitErrorEventFromEventListener = ( error , eventName ) => { error . eventName = eventName ; this . _emitErrorEvent ( error ) ; } ; _addErrorListener = ( newListener ) => { const eventName = "error" ; let listener = newListener ; const oldErrorEventListener = this . eventListeners . get ( eventName ) ; if ( oldErrorEventListener ) { listener = ( error ) => { newListener ( error ) ; oldErrorEventListener . listener ( error ) ; } ; } this . eventListeners . set ( eventName , { listener , } ) ; } ; _addEventListener = ( eventName , baseListener ) => { if ( eventName === "error" ) throw new Error ( `Use _addErrorListener function to subscribe to an error event.` ) ; if ( this . subscribedEventNames ( ) . includes ( eventName ) ) throw new Error ( `A listener for event '${ eventName }' is already registered.` ) ; const listener = async ( arg0 ) => { const eventListener = this . eventListeners . get ( eventName ) ; const { isRunning } = eventListener ; if ( isRunning ) { console . info ( `Listener is already running` ) ; return ; } this . decorateEventListener ( eventName , { isRunning : true , lastEmissionTime : Date . now ( ) , } ) ; this . _clearEventTimerIfExists ( eventName ) ; const timer = setTimeout ( ( ) => { const eventListener = this . eventListeners . get ( eventName ) ; const { lastEmissionTime } = eventListener ; const currentTime = Date . now ( ) ; const timedOut = currentTime - lastEmissionTime >= this . getTimeout ( ) ; if ( timedOut ) { this . _emitErrorEventFromEventListener ( new Error ( `Event ${ eventName } reached timeout.` ) , eventName ) ; } } , this . getTimeout ( ) ) ; this . decorateEventListener ( eventName , { timer } ) ; baseListener ( arg0 ) ; this . decorateEventListener ( eventName , { isRunning : false } ) ; } ; const eventListener = { listener , isRunning : false } ; this . eventListeners . set ( eventName , eventListener ) ; this . ethersEventEmitter . on ( this . _toEthersEventName ( eventName ) , listener ) ; } ; getEmitter = ( ) => { return this . ethersEventEmitter ; } ; private decorateEventListener = ( eventName , newArgs ) => { let eventListener = this . eventListeners . get ( eventName ) ; if ( ! eventListener ) return ; eventListener = { ... eventListener , ... newArgs } ; this . eventListeners . set ( eventName , eventListener ) ; } ; } export default Subscription ;