UNPKG

@bug-fix/drand-client

Version:

A client to the drand randomness beacon network.

85 lines (69 loc) 2.85 kB
import {Chain, ChainClient, ChainOptions, defaultChainOptions, RandomnessBeacon} from './index' import HttpCachingChain, {HttpChain} from './http-caching-chain' import {createSpeedTest, SpeedTest} from './speedtest' import HttpChainClient from './http-chain-client' const defaultSpeedTestInterval = 1000 * 60 * 5 type SpeedTestEntry = { test: SpeedTest url: string } // takes an array of drand nodes and periodically speed tests them to work out which is the fastest // it then uses the fastest client to make calls using an underlying HTTP client // use `.start()` to enable optimisation of the underlying base URLs // don't forget to `.stop()` it after you're finished class FastestNodeClient implements ChainClient { speedTests: Array<SpeedTestEntry> = [] speedTestHttpOptions = { userAgent: 'drand-web-client-speedtest' } constructor( public baseUrls: Array<string>, public options: ChainOptions = defaultChainOptions, private speedTestIntervalMs = defaultSpeedTestInterval ) { if (baseUrls.length === 0) { throw Error('Can\'t optimise an empty `baseUrls` array!') } } async latest(): Promise<RandomnessBeacon> { return new HttpChainClient(this.current(), this.options).latest() } async get(roundNumber: number): Promise<RandomnessBeacon> { return new HttpChainClient(this.current(), this.options).get(roundNumber) } chain(): Chain { return this.current() } start() { if (this.baseUrls.length === 1) { console.warn('There was only a single base URL in the `FastestNodeClient` - not running speed testing') return } this.speedTests = this.baseUrls.map(url => { const testFn = async () => { await new HttpChain(url, this.options, this.speedTestHttpOptions).info() return } const test = createSpeedTest(testFn, this.speedTestIntervalMs) test.start() return {test, url} } ) } current(): Chain { if (this.speedTests.length === 0) { console.warn('You are not currently running speed tests to choose the fastest client. Run `.start()` to speed test') } const fastestEntry = this.speedTests .slice() .sort((entry1, entry2) => entry1.test.average() - entry2.test.average()) .shift() if (!fastestEntry) { throw Error('Somehow there were no entries to optimise! This should be impossible by now') } return new HttpCachingChain(fastestEntry.url, this.options) } stop() { this.speedTests.forEach(entry => entry.test.stop()) this.speedTests = [] } } export default FastestNodeClient