server sided external api calls (#697)
* server sided external api calls * fix uploading gpx files * rename api/v1/nominatim with api/v1/geocoding to prepare photon support * remove NOMINATIM_MAX_RETRIES (side-kick from other PR) * re-add nominatim url fallback * docu, env var defaults and fallbacks, docker compose files * refactor * furhter refactorings and fixes * PUBLIC_VALHALLA_ENABLED in docker compose files added * fix env var names --------- Co-authored-by: Flomp <Flomp@users.noreply.github.com>
This commit is contained in:
63
web/src/lib/server/nominatim.ts
Normal file
63
web/src/lib/server/nominatim.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import { version } from "$app/environment";
|
||||
import { resolveBaseUrl } from "$lib/server/url";
|
||||
import type { RequestEvent } from "@sveltejs/kit";
|
||||
|
||||
const NOMINATIM_RATE_LIMIT_MS = 1000;
|
||||
const NOMINATIM_MAX_RETRIES = 2;
|
||||
let lastNominatimCall = 0;
|
||||
|
||||
function getNominatimBaseUrl(): string {
|
||||
return resolveBaseUrl("NOMINATIM_URL", "https://nominatim.openstreetmap.org");
|
||||
}
|
||||
|
||||
function needsRateLimiting(baseUrl: string): boolean {
|
||||
return baseUrl.includes("nominatim.openstreetmap.org");
|
||||
}
|
||||
|
||||
const waitTimer = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
async function nominatimRateLimiter(baseUrl: string) {
|
||||
if (!needsRateLimiting(baseUrl)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const elapsedTimeMs = Date.now() - lastNominatimCall;
|
||||
const waitTime = NOMINATIM_RATE_LIMIT_MS - elapsedTimeMs;
|
||||
if (waitTime > 0) {
|
||||
await waitTimer(waitTime);
|
||||
}
|
||||
|
||||
lastNominatimCall = Date.now();
|
||||
}
|
||||
|
||||
export async function fetchNominatim(event: RequestEvent, path: string, params: URLSearchParams): Promise<Response> {
|
||||
const baseUrl = getNominatimBaseUrl();
|
||||
const base = new URL(baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`);
|
||||
const cleanPath = path.replace(/^\/+/, "");
|
||||
const url = new URL(cleanPath, base);
|
||||
const query = params.toString();
|
||||
if (query.length) {
|
||||
url.search = query;
|
||||
}
|
||||
|
||||
let attempt = 0;
|
||||
|
||||
while (true) {
|
||||
await nominatimRateLimiter(baseUrl);
|
||||
|
||||
try {
|
||||
return await event.fetch(url.toString(), {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"User-Agent": `wanderer/${version}`,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
if (attempt < NOMINATIM_MAX_RETRIES) {
|
||||
attempt++;
|
||||
continue;
|
||||
}
|
||||
throw new Error(`Nominatim fetch failed for ${url.toString()}`, { cause: error });
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user