import { RadixAccount , logger } from '../..' ; import { RadixAddress , RadixAtom , RRI } from '../atommodel' ; import { Observable , BehaviorSubject , Subject , Subscription } from 'rxjs' ; import { TSMap } from 'typescript-map' ; import { filter , timeout , catchError , take , tap , share } from 'rxjs/operators' ; import { RadixTokenDefinition } from './RadixTokenDefinition' ; /**
 * A singleton class for loading information about tokens
 */ export class RadixTokenManager { public tokens : { [ id ] : RadixTokenDefinition ; } = { } ; private tokenSubscriptions : TSMap < string , BehaviorSubject < RadixTokenDefinition > > = new TSMap ( ) ; public accounts : TSMap < string , RadixAccount > = new TSMap ( ) ; private allTokenUpdateSubject : Subject < RadixTokenDefinition > = new Subject ( ) ; public nativeToken : RRI ; private initialized = false ; private subs = new Subscription ( ) ; public initialize ( nativeToken ) { this . accounts = new TSMap ( ) ; this . tokenSubscriptions . forEach ( subject => { subject . unsubscribe ( ) ; } ) ; this . tokenSubscriptions = new TSMap ( ) ; this . tokens = { } ; this . allTokenUpdateSubject . unsubscribe ( ) ; this . allTokenUpdateSubject = new Subject ( ) ; this . nativeToken = nativeToken ; const systemAccount = new RadixAccount ( nativeToken . address ) ; this . accounts . set ( systemAccount . getAddress ( ) , systemAccount ) ; this . addTokenDefinitionSubscription ( nativeToken . toString ( ) ) ; this . initialized = true ; } public async getTokenDefinitionObservable ( referenceURI ) { this . checkInitialized ( ) ; if ( ! this . tokenSubscriptions . has ( referenceURI ) ) { await this . addTokenDefinitionSubscription ( referenceURI ) ; } return this . tokenSubscriptions . get ( referenceURI ) . pipe ( share ( ) ) ; } private async addTokenDefinitionSubscription ( referenceURI ) { const reference = RRI . fromString ( referenceURI ) ; const account = await this . getAccount ( reference . getAddress ( ) ) ; const placeholderTokenDefinition = new RadixTokenDefinition ( reference . getAddress ( ) , reference . getName ( ) ) ; const bs = new BehaviorSubject ( placeholderTokenDefinition ) ; this . subs . add ( account . tokenDefinitionSystem . getTokenDefinitionObservable ( reference . getName ( ) ) . subscribe ( bs ) ) ; this . tokenSubscriptions . set ( referenceURI , bs ) ; this . subs . add ( bs . subscribe ( tokenDefinition => { this . tokens [ referenceURI ] = tokenDefinition ; } ) ) ; this . subs . add ( bs . subscribe ( this . allTokenUpdateSubject ) ) ; } public getTokenDefinition ( referenceURI ) { this . checkInitialized ( ) ; return new Promise ( ( resolve , reject ) => { const reference = RRI . fromString ( referenceURI ) ; this . getAccount ( reference . getAddress ( ) ) . then ( ( account ) => { this . subs . add ( account . isSynced ( ) . pipe ( filter ( val => val === true ) , take ( 1 ) , timeout ( 5000 ) ) . subscribe ( null , error => { logger . error ( error ) ; reject ( new Error ( 'Timeout tying to fetch token information from network' ) ) ; } , ( ) => { const tokenDefinition = account . tokenDefinitionSystem . getTokenDefinition ( reference . getName ( ) ) ; if ( tokenDefinition ) { resolve ( tokenDefinition ) ; } else { reject ( new Error ( 'Token definition does not exist in the account' ) ) ; } } ) ) ; } ) ; } ) ; } public getTokenDefinitionNoLoad ( referenceURI ) { return this . tokens [ referenceURI ] ; } private async getAccount ( address ) { if ( this . accounts . has ( address . toString ( ) ) ) { return this . accounts . get ( address . toString ( ) ) ; } else { const account = new RadixAccount ( address ) ; this . accounts . set ( address . toString ( ) , account ) ; return account ; } } private checkInitialized ( ) { if ( ! this . initialized ) { throw new Error ( 'Token Manager not initialized' ) ; } } public getAllTokenDefinitionUpdates ( ) { return this . allTokenUpdateSubject . pipe ( share ( ) ) ; } returns memberof public getCurrentTokens ( ) { this . checkInitialized ( ) ; return this . tokens ; } } export let radixTokenManager = new RadixTokenManager ( ) ;