Files
calculator/server.ts

68 lines
2.1 KiB
TypeScript

import { Hono } from 'hono'
import { serveStatic } from 'hono/bun'
import { Cron } from 'croner'
import { parseHTML } from 'linkedom'
import { z } from 'zod'
const units: Record<string, number> = {}
const app = new Hono()
app.use('/*', serveStatic({ root: './dist' }))
app.get('/api/units', (c) => c.json(units))
app.get('*', serveStatic({ root: './dist', path: 'index.html' }))
const updateExchangeRates = async () => {
const page = await fetch('https://www.cbr.ru/currency_base/daily/').then((d) => d.text())
const { document } = parseHTML(page)
const table = document.querySelector('div.table table')
if (table) {
const [_header, ...rows] = document.querySelectorAll('tr')
let amountOfUnits = 0
const codeParser = z.string().regex(/^[A-Z]{3}$/)
const amountParser = z.coerce.number().int()
const priceParser = z
.string()
.transform((val) => Number(val.replace('.', '$SPECIAL').replace(',', '.').replace('$SPECIAL', ',')))
.pipe(z.number())
for (const row of rows) {
const rowData: string[] = [...row.children].map((td) => td.textContent!).filter(Boolean)
const [_numberCode, _code, _amount, _description, _price] = rowData
try {
const code = codeParser.parse(_code)
const amount = amountParser.parse(_amount)
const price = priceParser.parse(_price)
units[code] = price / amount
amountOfUnits++
} catch (e) {
console.error(e)
}
}
console.log(`Загружен курс для ${amountOfUnits} валют`)
} else {
console.error('При запросе "https://www.cbr.ru/currency_base/daily/" на странице не найдена таблица')
}
}
updateExchangeRates()
new Cron(
'0 12 * * *',
{
name: 'updateExchangeRate',
timezone: 'Europe/Moscow',
catch: (e) => {
console.error(e)
},
},
updateExchangeRates,
)
export default app