@benshi.ai/js-sdk
Version:
Benshi SDK
131 lines (103 loc) • 3.84 kB
text/typescript
import { NetworkProxy } from "../../../drivers/network/typings"
import { CurrencyCode } from "../../commonTypes"
import * as defaultConversions from "./usd.json"
export interface Conversion {
usd: number
}
export interface ICurrencyRepository {
convertCurrencyToUSD(currencyFrom: CurrencyCode): Promise<Conversion>
}
interface PendingRequest {
currencyFrom: CurrencyCode
resolve: any
}
export default class CurrencyRepository implements ICurrencyRepository {
private url: string
private networkDriver: NetworkProxy
private cache
private requesting = false
private pendingRequests:Array<PendingRequest> = []
public constructor(url, networkDriver) {
this.url = url
this.networkDriver = networkDriver
const datesAreWithinAnHour = (newerDate, olderDate) => {
const ONE_HOUR = 60 * 60 * 1000
return (newerDate - olderDate) < ONE_HOUR
}
const cacheHandler = {
get: function(cache, currency) {
const now = new Date()
if ((cache[currency] !== undefined) && datesAreWithinAnHour(now, cache[currency].date)) {
return cache[currency]
} else {
return undefined
}
}
}
this.cache = new Proxy({}, cacheHandler)
}
private purgeQueue() {
// Those pending requests that already have a value in the cache will be resolved.
// For the rest, the process will start again by calling the `request` method
// again for them
const metaPendingRequests = this.pendingRequests.map( item => ({...item, ready: false}))
metaPendingRequests.forEach( (pendingRequest) => {
const {currencyFrom, resolve} = pendingRequest
if (this.cache[currencyFrom] !== undefined) {
resolve(this.cache[currencyFrom])
pendingRequest.ready = true
return
}
})
metaPendingRequests
.filter( request => !request.ready)
.forEach( request => this.request(request.currencyFrom, request.resolve))
this.pendingRequests = []
}
private request(currencyFrom, resolve) {
if (this.requesting) {
this.pendingRequests.push({currencyFrom, resolve})
return
}
this.requesting = true
this.networkDriver.get(`${this.url}?from=${currencyFrom}`).then((data) => {
let { usd } = data as Conversion
const now = new Date()
if (isNaN(usd) || usd === null) {
usd = 1 / defaultConversions.usd[currencyFrom.toLowerCase()]
} else {
this.cache[currencyFrom] = { date: now, usd: usd }
}
resolve({
usd: usd
})
this.requesting = false
this.purgeQueue()
}).catch(e => {
resolve({
usd: 1 / defaultConversions.usd[currencyFrom.toLowerCase()],
})
return
})
}
public convertCurrencyToUSD = (currencyFrom: CurrencyCode): Promise<Conversion> => {
return new Promise((resolve, reject) => {
if (currencyFrom === CurrencyCode.USD) {
resolve({
usd: 1
})
return
}
if ( this.cache[currencyFrom] !== undefined) {
resolve(this.cache[currencyFrom])
return
}
// this.request(currencyFrom, resolve)
const usd = 1 / defaultConversions.usd[currencyFrom.toLowerCase()]
this.cache[currencyFrom] = { date: new Date(), usd: usd }
resolve({
usd: usd
})
})
}
}