feat(clients/weather): in-memory cache
This commit is contained in:
parent
5c0a84b3eb
commit
2e029e47c0
3 changed files with 61 additions and 22 deletions
|
|
@ -26,6 +26,7 @@
|
|||
"eslint": "^9.39.1",
|
||||
"eslint-plugin-svelte": "^3.13.0",
|
||||
"globals": "^16.5.0",
|
||||
"node-cache": "^5.1.2",
|
||||
"svelte": "^5.43.8",
|
||||
"svelte-check": "^4.3.4",
|
||||
"tailwindcss": "^4.1.17",
|
||||
|
|
|
|||
17
pnpm-lock.yaml
generated
17
pnpm-lock.yaml
generated
|
|
@ -47,6 +47,9 @@ importers:
|
|||
globals:
|
||||
specifier: ^16.5.0
|
||||
version: 16.5.0
|
||||
node-cache:
|
||||
specifier: ^5.1.2
|
||||
version: 5.1.2
|
||||
svelte:
|
||||
specifier: ^5.43.8
|
||||
version: 5.45.2
|
||||
|
|
@ -679,6 +682,10 @@ packages:
|
|||
class-variance-authority@0.7.1:
|
||||
resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==}
|
||||
|
||||
clone@2.1.2:
|
||||
resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==}
|
||||
engines: {node: '>=0.8'}
|
||||
|
||||
clsx@2.1.1:
|
||||
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
|
||||
engines: {node: '>=6'}
|
||||
|
|
@ -1034,6 +1041,10 @@ packages:
|
|||
natural-compare@1.4.0:
|
||||
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
||||
|
||||
node-cache@5.1.2:
|
||||
resolution: {integrity: sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==}
|
||||
engines: {node: '>= 8.0.0'}
|
||||
|
||||
optionator@0.9.4:
|
||||
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
|
@ -1801,6 +1812,8 @@ snapshots:
|
|||
dependencies:
|
||||
clsx: 2.1.1
|
||||
|
||||
clone@2.1.2: {}
|
||||
|
||||
clsx@2.1.1: {}
|
||||
|
||||
color-convert@2.0.1:
|
||||
|
|
@ -2133,6 +2146,10 @@ snapshots:
|
|||
|
||||
natural-compare@1.4.0: {}
|
||||
|
||||
node-cache@5.1.2:
|
||||
dependencies:
|
||||
clone: 2.1.2
|
||||
|
||||
optionator@0.9.4:
|
||||
dependencies:
|
||||
deep-is: 0.1.4
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import NodeCache from "node-cache";
|
||||
import crypto from "node:crypto";
|
||||
|
||||
/**
|
||||
|
|
@ -10,6 +11,14 @@ const USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
|
|||
*/
|
||||
const WEATHER_TOKEN_SECRET = "gravisfrontem";
|
||||
|
||||
/**
|
||||
* Response cache.
|
||||
*/
|
||||
const cache = new NodeCache({
|
||||
// NOTE: 10 minutes in a seconds
|
||||
stdTTL: 60 * 10,
|
||||
});
|
||||
|
||||
interface YandexWeatherData {
|
||||
/**
|
||||
* Message from the server.
|
||||
|
|
@ -18,54 +27,54 @@ interface YandexWeatherData {
|
|||
|
||||
info: {
|
||||
/**
|
||||
* URL of the location page on Yandex Weather
|
||||
* URL of the location page on Yandex Weather.
|
||||
**/
|
||||
url: string;
|
||||
};
|
||||
|
||||
fact: {
|
||||
/**
|
||||
* Current air temperature in °C
|
||||
* Current air temperature in °C.
|
||||
**/
|
||||
temp: number;
|
||||
|
||||
/**
|
||||
* Water temperature in °C (may be missing)
|
||||
* Water temperature in °C.
|
||||
**/
|
||||
temp_water?: number;
|
||||
|
||||
/**
|
||||
* Perceived (“feels like”) temperature in °C
|
||||
* Perceived (“feels like”) temperature in °C.
|
||||
**/
|
||||
feels_like: number;
|
||||
|
||||
/**
|
||||
* Weather condition code (e.g., "clear", "rain")
|
||||
* Weather condition code (e.g., "clear", "rain").
|
||||
**/
|
||||
condition: string;
|
||||
|
||||
/**
|
||||
* Wind speed in m/s
|
||||
* Wind speed in m/s.
|
||||
**/
|
||||
wind_speed: number;
|
||||
|
||||
/**
|
||||
* Wind gust speed in m/s (may be missing)
|
||||
* Wind gust speed in m/s.
|
||||
**/
|
||||
wind_gust?: number;
|
||||
|
||||
/**
|
||||
* Wind direction code (e.g., "nw", "s")
|
||||
* Wind direction.
|
||||
**/
|
||||
wind_dir: string;
|
||||
|
||||
/**
|
||||
* Atmospheric pressure in mmHg
|
||||
* Atmospheric pressure in mmHg.
|
||||
**/
|
||||
pressure_mm: number;
|
||||
|
||||
/**
|
||||
* Air humidity percentage
|
||||
* Air humidity percentage.
|
||||
**/
|
||||
humidity: number;
|
||||
};
|
||||
|
|
@ -111,7 +120,7 @@ export interface FetchWeatherResult {
|
|||
gust?: number;
|
||||
|
||||
/**
|
||||
* Wind direction code.
|
||||
* Wind direction.
|
||||
**/
|
||||
direction: string;
|
||||
};
|
||||
|
|
@ -140,20 +149,32 @@ function getWeatherHeaders() {
|
|||
}
|
||||
|
||||
export default async function fetchWeather(lat: number, lon: number): Promise<FetchWeatherResult> {
|
||||
const response = await fetch(
|
||||
`https://api.weather.yandex.ru/v2/informers?lat=${lat}&lon=${lon}&lang=en_US`,
|
||||
{
|
||||
headers: {
|
||||
'user-agent': USER_AGENT,
|
||||
...getWeatherHeaders(),
|
||||
},
|
||||
const key = `${lat};${lon}`
|
||||
|
||||
let result: YandexWeatherData | undefined = cache.get(key);
|
||||
if (!result) {
|
||||
const response = await fetch(
|
||||
`https://api.weather.yandex.ru/v2/informers?lat=${lat}&lon=${lon}&lang=en_US`,
|
||||
{
|
||||
headers: {
|
||||
'user-agent': USER_AGENT,
|
||||
...getWeatherHeaders(),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
result = await response.json();
|
||||
|
||||
// NOTE: to fix with typescript errors
|
||||
if (!result) {
|
||||
throw new Error('Result is undefined')
|
||||
}
|
||||
);
|
||||
|
||||
const result: YandexWeatherData = await response.json();
|
||||
if (!response.ok) {
|
||||
throw new Error(result.message!)
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Yandex Weather API error: ${result.message}`)
|
||||
cache.set(key, result);
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue