import { ApiPromise , WsProvider } from "@polkadot/api" ; import EventEmitter from "eventemitter3" ; import logger from "./logger" ; import { sleep } from "./util" ; /**
 * A higher level handler for the Polkadot-Js API that can handle reconnecting
 * to a different provider if one proves troublesome.
 */ class ApiHandler extends EventEmitter { private _api : ApiPromise ; private _endpoints : string [ ] ; private _reconnectLock : boolean ; private _reconnectTries = 0 ; static isConnected : any ; static _reconnect : any ; constructor ( api , endpoints ) { super ( ) ; this . _api = api ; this . _endpoints = endpoints ; this . _registerEventHandlers ( api ) ; } static async createApi ( endpoints ) { const api = new ApiPromise ( { provider : new WsProvider ( endpoints ) , } ) ; if ( api ) { api . on ( "connected" , ( ) => { logger . info ( `Connected to chain` ) ; } ) . on ( "disconnected" , async ( ) => { logger . warn ( `Disconnected from chain` ) ; } ) . on ( "ready" , ( ) => { logger . info ( `API connection ready` ) ; } ) . on ( "error" , ( error ) => { logger . warn ( "The API has an error" ) ; console . log ( error ) ; } ) ; await api . isReadyOrError ; return api ; } } static async create ( endpoints ) { try { const api = await this . createApi ( endpoints ) ; return new ApiHandler ( api , endpoints ) ; } catch ( e ) { logger . info ( `there was an error: ` ) ; console . log ( e ) ; } } isConnected ( ) { return this . _api . isConnected ; } async getApi ( ) { if ( this . _reconnectLock ) { return new Promise ( ( resolve ) => { setTimeout ( ( ) => resolve ( this . getApi ( ) ) , 2000 ) ; } ) ; } return this . _api ; } _registerEventHandlers ( api ) { api . query . system . events ( ( events ) => { events . forEach ( ( record ) => { const { event } = record ; if ( event . section == "session" && event . method == "NewSession" ) { const [ session_index ] = event . data ; this . emit ( "newSession" , { sessionIndex : session_index . toString ( ) , } ) ; } if ( event . section == "staking" && ( event . method == "Reward" || event . method == "Rewarded" ) ) { const [ stash , amount ] = event . data ; this . emit ( "reward" , { stash : stash . toString ( ) , amount : amount . toString ( ) , } ) ; } if ( event . section === "imOnline" && event . method === "SomeOffline" ) { const offlineVals = event . data . toJSON ( ) [ 0 ] . map ( ( val ) => val [ 0 ] ) ; this . emit ( "someOffline" , { offlineVals : offlineVals , } ) ; } } ) ; } ) ; } async _reconnect ( ) { if ( this . _reconnectLock ) { logger . info ( `API Already Trying Reconnect...` ) ; return ; } logger . info ( `API Disconnected... Reconnecting... (reconnect tries: ${ this . _reconnectTries })` ) ; this . _reconnectLock = true ; this . _reconnectTries ++ ; this . _api . disconnect ( ) ; const nextEndpoint = this . _endpoints [ this . _reconnectTries % 5 ] ; const api = await ApiPromise . create ( { provider : new WsProvider ( nextEndpoint ) , } ) ; this . _registerEventHandlers ( api ) ; this . _api = api ; this . _reconnectLock = false ; } } export default ApiHandler ;