62 lines
1.8 KiB
TypeScript
62 lines
1.8 KiB
TypeScript
import { nextTuesdayDeparture } from "@transportationer/shared";
|
|
|
|
const VALHALLA_BASE = process.env.VALHALLA_URL ?? "http://valhalla:8002";
|
|
const VALHALLA_TRANSIT_BASE = process.env.VALHALLA_TRANSIT_URL ?? VALHALLA_BASE;
|
|
|
|
export type ValhallaCosting = "pedestrian" | "bicycle" | "auto";
|
|
|
|
const COSTING_MAP: Record<string, ValhallaCosting> = {
|
|
walking: "pedestrian",
|
|
cycling: "bicycle",
|
|
driving: "auto",
|
|
};
|
|
|
|
export interface IsochroneOpts {
|
|
lng: number;
|
|
lat: number;
|
|
travelMode: string;
|
|
contourMinutes: number[];
|
|
polygons?: boolean;
|
|
}
|
|
|
|
export async function fetchIsochrone(opts: IsochroneOpts): Promise<object> {
|
|
const isTransit = opts.travelMode === "transit";
|
|
const costing = isTransit ? "multimodal" : (COSTING_MAP[opts.travelMode] ?? "pedestrian");
|
|
const body: Record<string, unknown> = {
|
|
locations: [{ lon: opts.lng, lat: opts.lat }],
|
|
costing,
|
|
contours: opts.contourMinutes.map((time) => ({ time })),
|
|
polygons: opts.polygons ?? true,
|
|
show_locations: false,
|
|
};
|
|
if (isTransit) {
|
|
body.costing_options = { transit: { use_bus: 1.0, use_rail: 1.0, use_transfers: 1.0 } };
|
|
body.date_time = { type: 1, value: nextTuesdayDeparture() };
|
|
}
|
|
|
|
const base = isTransit ? VALHALLA_TRANSIT_BASE : VALHALLA_BASE;
|
|
const res = await fetch(`${base}/isochrone`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify(body),
|
|
signal: AbortSignal.timeout(30_000),
|
|
});
|
|
|
|
if (!res.ok) {
|
|
const text = await res.text();
|
|
throw new Error(`Valhalla error ${res.status}: ${text}`);
|
|
}
|
|
|
|
return res.json();
|
|
}
|
|
|
|
export async function checkValhalla(): Promise<boolean> {
|
|
try {
|
|
const res = await fetch(`${VALHALLA_BASE}/status`, {
|
|
signal: AbortSignal.timeout(3000),
|
|
});
|
|
return res.ok;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|