Skip to content

Commit 7373849

Browse files
authored
Merge pull request #109 from EdgeApp/jon/fix/non-usd-coinrank
Fix: Non-USD coinrank requests returning USD results
2 parents a1f7fd7 + 9c3b931 commit 7373849

File tree

2 files changed

+66
-16
lines changed

2 files changed

+66
-16
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Unreleased
44

5+
- fixed: Non-USD coinrank rate requests were intermittently returning USD results
56
- fixed: `coinrank?fiatCode=iso:[fiatCode]` was not calculating fiat exchange rates for all relevant fields
67

78
## 0.2.0 (2024-04-16)

src/exchangeRateRouter.ts

Lines changed: 65 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
addIso,
2929
fromCode,
3030
isIsoCode,
31+
logger,
3132
normalizeDate,
3233
subIso,
3334
toCode,
@@ -329,34 +330,70 @@ const getRedisMarkets = async (
329330
const now = new Date()
330331
const nowTimestamp = now.getTime()
331332

332-
const jsonString = await getAsync(`${REDIS_COINRANK_KEY_PREFIX}_${fiatCode}`)
333-
let redisResult: CoinrankRedis = JSON.parse(jsonString)
333+
try {
334+
// First try to get data for the requested fiat code
335+
const jsonString = await getAsync(
336+
`${REDIS_COINRANK_KEY_PREFIX}_${fiatCode}`
337+
)
334338

335-
if (fiatCode !== defaultFiatCode) {
336-
const lastUpdated =
337-
redisResult != null ? new Date(redisResult.lastUpdate).getTime() : 0
339+
// Only parse if jsonString is not null/undefined
340+
let redisResult: CoinrankRedis | undefined
341+
if (jsonString != null) {
342+
try {
343+
redisResult = JSON.parse(jsonString)
344+
345+
// If we have valid data that hasn't expired, return it
346+
const lastUpdated =
347+
redisResult != null ? new Date(redisResult.lastUpdate).getTime() : 0
348+
if (nowTimestamp - lastUpdated <= EXPIRE_TIME) {
349+
return redisResult
350+
}
351+
// We have cached data but it's expired - we'll try to refresh it below
352+
// but will fall back to this expired data if refresh fails
353+
} catch (e) {
354+
// JSON parsing error, redisResult remains undefined
355+
logger(`Error parsing Redis data for ${fiatCode}: ${e}`)
356+
// Continue to try to get fresh data
357+
}
358+
}
338359

339-
// If no result in redis or it's out of date
340-
if (redisResult == null || nowTimestamp - lastUpdated > EXPIRE_TIME) {
341-
// Attempt to scale prices by foreign exchange rate
360+
// For USD requests, return the result immediately (could be undefined if not found)
361+
if (fiatCode === defaultFiatCode) {
362+
return redisResult
363+
}
342364

365+
// If we need to convert from USD (either no data or expired data)
366+
try {
343367
// Get exchange rate
344368
const result = await fetch(
345369
`${ratesServerAddress}/v2/exchangeRate?currency_pair=${defaultFiatCode}_${fiatCode}`
346370
)
371+
if (!result.ok) {
372+
throw new Error(`Exchange rate API returned status ${result.status}`)
373+
}
374+
347375
const resultJson = await result.json()
348376
const { exchangeRate } = asExchangeRateResponse(resultJson)
349377
const rate = Number(exchangeRate)
350378

379+
// Validate the rate
380+
if (rate == null || isNaN(rate) || rate <= 0) {
381+
throw new Error(`Invalid exchange rate: ${exchangeRate}`)
382+
}
383+
351384
// Get USD rankings
352-
const jsonString = await getAsync(
385+
const usdJsonString = await getAsync(
353386
`${REDIS_COINRANK_KEY_PREFIX}_${defaultFiatCode}`
354387
)
355-
redisResult = JSON.parse(jsonString)
356-
let { markets } = redisResult
388+
if (usdJsonString == null) {
389+
throw new Error(`No USD data available in Redis`)
390+
}
391+
392+
const usdRedisResult = JSON.parse(usdJsonString)
393+
const { markets } = usdRedisResult
357394

358395
// Modify fiat-related fields with the forex rate
359-
markets = markets.map(m => ({
396+
const convertedMarkets = markets.map(m => ({
360397
...m,
361398
marketCap: m.marketCap * rate,
362399
price: m.price * rate,
@@ -374,17 +411,29 @@ const getRedisMarkets = async (
374411

375412
// Update redis cache
376413
const redisData: CoinrankRedis = {
377-
markets,
378-
lastUpdate: now.toISOString()
414+
markets: convertedMarkets,
415+
lastUpdate: redisResult?.lastUpdate ?? now.toISOString()
379416
}
380417
await setAsync(
381418
`${REDIS_COINRANK_KEY_PREFIX}_${fiatCode}`,
382419
JSON.stringify(redisData)
383420
)
421+
422+
return redisData
423+
} catch (e) {
424+
logger(`Error converting USD data to ${fiatCode}: ${e}`)
425+
// If conversion fails but we have cached data (even if expired), return that
426+
if (redisResult != null) {
427+
logger(`Falling back to cached data for ${fiatCode}`)
428+
return redisResult
429+
}
430+
// Only return undefined if we have no cached data at all
431+
return undefined
384432
}
433+
} catch (e) {
434+
logger(`Error in getRedisMarkets for ${fiatCode}: ${e}`)
435+
return undefined
385436
}
386-
387-
return redisResult
388437
}
389438

390439
const sendCoinrankList: express.RequestHandler = async (

0 commit comments

Comments
 (0)