UNPKG

@infect/infect-rda-sample-importer

Version:
114 lines (81 loc) 3.09 kB
import LRUCache from 'lru-cache'; import { setTimeout } from 'timers/promises'; import logd from 'logd'; const log = logd.module('APILookup'); export default class APILookup { constructor({ cacheTTL = 3600, cacheSize = 10000, httpClient, resource, filterProperty = 'identifier', selectionField = 'id', selectionHeader = '*', filterHader = '', }) { this.selectionHeader = selectionHeader; this.filterHader = filterHader; // the resource to load this.httpClient = httpClient; this.resource = resource; this.property = filterProperty; // optional return field this.field = selectionField; // cache looked up items this.cache = new LRUCache({ max: cacheSize, ttl: cacheTTL * 1000, }); } async end() { this.httpClient.end(); } async get(key) { // escape commas, the api will unescape them key = key.replace(/,/g, ';;'); //log.debug(`Looking up key '${key}'`); if (!this.cache.has(key)) { //log.debug(`Key '${key}' is not in the cache, querying the API`); let filter = `${this.property}=${key}`; // add a custom filter if required if (this.filterHader) { filter += `, ${this.filterHader}`; } // issue the request const promise = this.sendRequest(filter, key); this.cache.set(key, promise); } return this.cache.get(key); } async sendRequest(filter, key, retryCount = 0) { try { const response = await this.httpClient.get(`/core-data/v1/${this.resource}`) .setHeader('filter', filter) .setHeader('select', this.selectionHeader) .send(); const data = await response.getData(); if (data && data.length) { if (this.field) return data[0][this.field]; else return data[0]; } else { const err = new Error(`Failed to load value for key '${key}' from ${this.httpClient.hostname}/${this.resource}`); err.failedLookup = true; err.resource = this.resource; err.property = this.property; err.unresolvedValue = key; throw err; } } catch (err) { if ((err.message.includes('NGHTTP2_REFUSED_STREAM') || err.message.includes('NGHTTP2_ENHANCE_YOUR_CALM')) && retryCount < 5) { const backoffTime = (retryCount + 1) * 100; log.warn(`API-Lookup failed: stream was closed, trying again in ${backoffTime}ms`); // back off a bit await setTimeout(backoffTime); // try again return await this.sendRequest(filter, key, retryCount + 1); } else { throw err; } } } }