70 lines
1.6 KiB
JavaScript
70 lines
1.6 KiB
JavaScript
const CRON_EXPRESSION = '0 17 * * *';
|
|
|
|
/**
|
|
* Importiert oder aktualisiert Währungskurse in PocketBase.
|
|
* Das 'updated'-Feld wird durch die Collection als Autodate verwaltet.
|
|
*/
|
|
function runImport() {
|
|
const ECB_URL =
|
|
'https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml';
|
|
const COLLECTION_NAME = 'currencies';
|
|
const IMPORT_TIMEOUT_MS = 30000;
|
|
|
|
/**
|
|
* Extrahiert Währungskurse aus dem ECB-XML.
|
|
*
|
|
* @param {string} xml - Rohe XML-Antwort.
|
|
* @returns {Array<{currency: string, rate: number}>}
|
|
*/
|
|
function parseRates(xml) {
|
|
const CURRENCY_RATE_REGEX =
|
|
/<Cube\s+[^>]*currency='([^']+)'[^>]*rate='([^']+)'[^>]*\/>/g;
|
|
const rates = [];
|
|
let match;
|
|
while ((match = CURRENCY_RATE_REGEX.exec(xml)) !== null) {
|
|
rates.push({
|
|
currency: match[1].toLowerCase(),
|
|
rate: parseFloat(match[2]),
|
|
});
|
|
}
|
|
return rates;
|
|
}
|
|
|
|
const response = $http.send({
|
|
url: ECB_URL,
|
|
method: 'GET',
|
|
timeout: IMPORT_TIMEOUT_MS,
|
|
});
|
|
|
|
if (response.statusCode !== 200) {
|
|
throw new Error(
|
|
'Failed to fetch ECB rates: HTTP ' + response.statusCode,
|
|
);
|
|
}
|
|
|
|
const rates = parseRates(response.raw);
|
|
|
|
if (rates.length === 0) {
|
|
throw new Error('No rates found in ECB response');
|
|
}
|
|
|
|
const collection = $app.findCollectionByNameOrId(COLLECTION_NAME);
|
|
|
|
for (const item of rates) {
|
|
let record;
|
|
try {
|
|
record = $app.findRecordById(
|
|
COLLECTION_NAME,
|
|
item.currency,
|
|
);
|
|
} catch (e) {
|
|
record = new Record(collection);
|
|
record.id = item.currency;
|
|
}
|
|
record.set('rate', item.rate);
|
|
$app.save(record);
|
|
}
|
|
}
|
|
|
|
cronAdd('import-currencies', CRON_EXPRESSION, runImport);
|