@infect/infect-rda-sample-importer
Version:
INFECT Sample Data Importer
114 lines (81 loc) • 3.09 kB
JavaScript
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;
}
}
}
}