59bfe2013f
Replace the hardcoded lane: 0 on input_received events with a real device->lane lookup. A new LaneMap caches lane_devices.id -> lane, built at startup and refreshed by the setup routes on assign/unassign. An unmapped device logs lane: -1 + a warning (0 is a real lane) and is still recorded faithfully (append-only chain). source stays null for raw inputs by design: it's an IdentitySource (how a vehicle was identified), not a device field; device provenance remains in identity. Documented both in the wiki.
31 lines
1.1 KiB
TypeScript
31 lines
1.1 KiB
TypeScript
import { laneDevices, type Db } from "@parking/db";
|
|
|
|
// Resolves a device instance id (lane_devices.id) to its lane number.
|
|
//
|
|
// Device pushes/events carry the `lane_devices` id (which device fired), not a
|
|
// lane. The event log wants the lane, so we keep a small in-memory id->lane map
|
|
// rebuilt from the DB at startup and refreshed whenever assignments change
|
|
// (assign/unassign). It's tiny (one row per device) and read on the hot path of
|
|
// every input event, so a cached map beats a per-event DB lookup.
|
|
export class LaneMap {
|
|
readonly #db: Db;
|
|
#byDeviceId = new Map<string, number>();
|
|
|
|
constructor(db: Db) {
|
|
this.#db = db;
|
|
}
|
|
|
|
/** (Re)load the id->lane map from the lane_devices table. */
|
|
refresh(): void {
|
|
const rows = this.#db.select().from(laneDevices).all();
|
|
const next = new Map<string, number>();
|
|
for (const r of rows) next.set(r.id, r.lane);
|
|
this.#byDeviceId = next;
|
|
}
|
|
|
|
/** Lane for a device instance id, or null if the device isn't known. */
|
|
laneFor(deviceId: string): number | null {
|
|
return this.#byDeviceId.get(deviceId) ?? null;
|
|
}
|
|
}
|