import Rpc from '@polkadot/rpc-core' ; import { WsProvider } from '@polkadot/rpc-provider' ; import { ProviderInterface } from '@polkadot/rpc-provider/types' ; import { Text , TypeRegistry } from '@polkadot/types' ; import { BlockHash , ChainProperties , Header , Health , } from '@polkadot/types/interfaces' ; import { Codec } from '@polkadot/types/types' ; import { logger } from '@polkadot/util' ; import React , { useEffect , useRef , useState } from 'react' ; import { combineLatest , interval , merge , MonoTypeOperatorFunction } from 'rxjs' ; import { distinctUntilChanged , filter , switchMap , take } from 'rxjs/operators' ; import { providerConnected } from './util' ; /**
 * Like distinctUntilChanged, but for Codecs
 */ function distinctCodecChanged < T extends Codec > ( ) { return distinctUntilChanged < T > ( ( x , y ) => x . eq ( y ) ) ; } /**
 * System-wide meta-information about the chain (nothing from its state)
 */ export interface SystemContextType { chain ? : Text ; genesisHash ? : BlockHash ; header ? : Header ; health ? : Health ; isSystemReady : boolean ; name ? : Text ; properties ? : ChainProperties ; version ? : Text ; } const l = logger ( 'system-context' ) ; export const SystemContext = React . createContext ( { } as SystemContextType ) ; export interface SystemContextProviderProps { children ? : React . ReactElement ; provider ? : ProviderInterface ; } export function SystemContextProvider ( props ) { const { children = null , provider } = props ; const [ chain , setChain ] = useState < Text > ( ) ; const [ genesisHash , setGenesisHash ] = useState < BlockHash > ( ) ; const [ header , setHeader ] = useState < Header > ( ) ; const [ health , setHealth ] = useState < Health > ( ) ; const [ name , setName ] = useState < Text > ( ) ; const [ properties , setProperties ] = useState < ChainProperties > ( ) ; const [ version , setVersion ] = useState < Text > ( ) ; const registryRef = useRef ( new TypeRegistry ( ) ) ; const [ rpc , setRpc ] = useState < Rpc > ( ) ; useEffect ( ( ) => { setChain ( undefined ) ; setGenesisHash ( undefined ) ; setHeader ( undefined ) ; setHealth ( undefined ) ; setName ( undefined ) ; setProperties ( undefined ) ; setVersion ( undefined ) ; if ( ! provider ) { return ; } setRpc ( new Rpc ( registryRef . current , provider ) ) ; } , [ provider ] ) ; useEffect ( ( ) => { if ( ! provider || ! rpc ) { return ; } const sub = providerConnected ( provider ) . pipe ( filter ( connected => ! ! connected ) , switchMap ( ( ) => combineLatest ( [ rpc . system . chain ( ) , rpc . chain . getBlockHash ( 0 ) , rpc . system . name ( ) , rpc . system . properties ( ) , rpc . system . version ( ) , ] ) ) , take ( 1 ) ) . subscribe ( ( [ _chain , _genesisHash , _name , _properties , _version ] ) => { l . log ( `Rpc connected to chain "${ _chain }" with properties ${ JSON . stringify ( _properties ) } via ${ provider instanceof WsProvider ? provider . endpoint : provider . constructor . name }` ) ; setChain ( _chain ) ; setGenesisHash ( _genesisHash ) ; setName ( _name ) ; setProperties ( _properties ) ; setVersion ( _version ) ; } ) ; return ( ) : void => sub . unsubscribe ( ) ; } , [ provider , rpc ] ) ; useEffect ( ( ) => { if ( ! provider || ! rpc ) { return ; } const sub = providerConnected ( provider ) . pipe ( filter ( connected => ! ! connected ) , switchMap ( ( ) => combineLatest ( [ merge ( rpc . chain . subscribeNewHeads ( ) , interval ( 2000 ) . pipe ( switchMap ( ( ) => rpc . chain . getHeader ( ) ) ) ) . pipe ( distinctCodecChanged ( ) ) , interval ( 2000 ) . pipe ( switchMap ( ( ) => rpc . system . health ( ) ) , distinctCodecChanged ( ) ) , ] ) ) ) . subscribe ( ( [ _header , _health ] ) => { setHeader ( _header ) ; setHealth ( _health ) ; } ) ; return ( ) : void => sub . unsubscribe ( ) ; } , [ provider , rpc ] ) ; return ( < SystemContext . Provider value = { { chain , genesisHash , header , health , isSystemReady : ! ! ( chain && genesisHash && header && health && name && properties && version ) , name , properties , version , } } > { children } < /SystemContext.Provider>); }