navigator/src/lib/routing.worker.ts

53 lines
1.8 KiB
TypeScript

/**
* routing.worker.ts — runs route computation off the UI thread.
* ----------------------------------------------------------------------
* The main thread posts a RouteJob; this worker runs `routeWithProgress`
* (which yields periodically and reports progress) and posts back:
*
* { type: 'progress', pct: number }
* { type: 'done', result: RouteResult, token: number }
* { type: 'error', message: string, token: number }
*
* A `token` distinguishes runs so a stale/obsolete in-flight job can be
* ignored by the pe; worker stays single-flight per post.
*/
import { routeWithProgress } from './routing';
import type { RouteGraph, AvoidRule, RouteResult } from './routing';
export interface RouteJob {
type: 'route';
token: number;
graph: RouteGraph;
pois: Array<{ type: 'Feature'; properties: Record<string, unknown>; geometry: { type: string; coordinates: number[] } }>;
from: [number, number];
to: [number, number];
avoid: AvoidRule[];
/** Approximate fraction to send as progress during the search. */
onEvery?: number;
}
type WorkerReply =
| { type: 'progress'; pct: number; token: number }
| { type: 'done'; result: RouteResult; token: number }
| { type: 'error'; message: string; token: number };
self.onmessage = (e: MessageEvent<RouteJob>) => {
const job = e.data;
if (!job || job.type !== 'route') return;
const { token, graph, pois, from, to, avoid } = job;
const send = (msg: WorkerReply) => {
(self as unknown as {
postMessage: (m: WorkerReply, transfer?: Transferable[]) => void;
}).postMessage(msg);
};
void routeWithProgress(graph, from, to, pois as GeoJSON.Feature[], avoid, (pct) => {
send({ type: 'progress', pct, token });
})
.then((result) => send({ type: 'done', result, token }))
.catch((err) =>
send({ type: 'error', message: err instanceof Error ? err.message : String(err), token })
);
};