atriusmaps-node-sdk
Version:
This project provides an API to Atrius Personal Wayfinder maps within a Node environment. See the README.md for more information
150 lines (146 loc) • 5.5 kB
JavaScript
;
var Zousan = require('zousan');
var processors = require('./processors.js');
let REFRESH_FREQUENCY = 1e3 * 30;
const MARKETPLACE_URL_BASE = "https://marketplace.locuslabs.com";
const MAX_FETCH_FAILS = 3;
const ACCOUNT_ID_HEADER = "x-account-id";
const isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
function create(app, config = {}) {
const state = {
dynamicDataNotPending: new Zousan()
};
const T = app.gt();
const getSecurityWaitTimes = async ({ isOpen } = {}) => {
const pois = await app.bus.get("poi/getAll");
return Object.values(pois).filter(
(poi) => poi.category === "security.checkpoint" && poi?.dynamicData?.security && isObject(poi?.dynamicData?.security) && (isOpen === void 0 ? true : poi?.dynamicData?.security?.isTemporarilyClosed !== isOpen)
).map((poi) => ({
id: poi.poiId,
name: poi.name,
...poi.dynamicData.security
}));
};
if (config._overrideRefreshFrequency) {
REFRESH_FREQUENCY = config._overrideRefreshFrequency;
}
const previousNameOverrides = /* @__PURE__ */ new Map();
app.bus.on("system/readywhenyouare", () => state.dynamicDataNotPending);
app.bus.on("dynamicPois/getSecurityWaitTimes", getSecurityWaitTimes);
const init = async () => {
const [accountId, venueId] = await Promise.all([
app.bus.get("venueData/getAccountId"),
app.bus.get("venueData/getVenueId")
]);
const dynamicPoisUrl = `${MARKETPLACE_URL_BASE}/venueId/${venueId}/dynamic-poi`;
let fetchFailuresCount = 0;
let fetchSuccessCount = 0;
let fetchIntervalHandle;
const updateFromAPI = async () => {
const response = await fetch(dynamicPoisUrl, {
headers: { [ACCOUNT_ID_HEADER]: accountId }
});
if (response.ok) {
return response.json().then(({ data }) => processDynamicPois(data)).then(() => {
fetchSuccessCount++;
}).catch(console.error);
} else {
console.warn("dynamicPois: fetch response status not ok", response);
fetchFailuresCount++;
if (fetchFailuresCount >= MAX_FETCH_FAILS && fetchFailuresCount > fetchSuccessCount) {
clearInterval(fetchIntervalHandle);
}
}
};
await updateFromAPI().then(() => {
fetchIntervalHandle = setInterval(updateFromAPI, REFRESH_FREQUENCY);
if (typeof fetchIntervalHandle.unref === "function") {
fetchIntervalHandle.unref();
}
}).finally(() => state.dynamicDataNotPending.resolve(true));
return () => clearInterval(fetchIntervalHandle);
};
async function processDynamicPois(pois) {
processParkingPOIS(pois);
processOpenClosedPois(pois);
processSecurityWaitTimes(pois);
processDynamicRouting(pois);
processDynamicAttributes(pois);
}
async function processDynamicAttributes(poiDataMap) {
const updates = {};
for (const [poiId, poiData] of Object.entries(poiDataMap)) {
const name = poiData?.dynamicData?.poiAttributes?.name ?? null;
const previous = previousNameOverrides.get(poiId);
if (previous === void 0) {
if (name !== null) {
updates[poiId] = { name };
previousNameOverrides.set(poiId, name);
}
} else if (previous !== name) {
updates[poiId] = { name };
previousNameOverrides.set(poiId, name);
}
}
for (const [poiId, prevName] of previousNameOverrides.entries()) {
if (!(poiId in poiDataMap) && prevName !== null) {
updates[poiId] = { name: null };
previousNameOverrides.set(poiId, null);
}
}
if (Object.keys(updates).length > 0) {
app.bus.send("poi/setCoreAttributes", updates);
const originalNames = await getPoiOriginalNames(Object.keys(updates));
app.bus.send("map/mutateFeature", {
functor: processors.mutatePoiName(T, updates, originalNames)
});
}
}
function processParkingPOIS(poiMap) {
const idValuesMap = processors.processParkingPOIS(poiMap);
app.bus.send("poi/setDynamicData", { plugin: "parking", idValuesMap });
}
const getPOILabels = async (idArray) => {
const nameMap = {};
for (const poiId of idArray) {
const poi = await app.bus.get("poi/getById", { id: poiId });
if (poi) {
nameMap[poiId] = poi.name;
}
}
return nameMap;
};
const getPoiOriginalNames = async (idArray) => {
const nameMap = {};
for (const poiId of idArray) {
const poi = await app.bus.get("poi/getById", { id: poiId });
if (poi) {
nameMap[poiId] = poi.staticName ?? poi.name;
}
}
return nameMap;
};
async function processSecurityWaitTimes(poiMap) {
const idValuesMap = processors.processSecurityWaitTimes(poiMap);
app.bus.send("poi/setDynamicData", { plugin: "security", idValuesMap });
const labels = await getPOILabels(Object.keys(idValuesMap));
app.bus.send("map/mutateFeature", {
functor: processors.mutateSecurityCheckpointLabel(T, idValuesMap, labels)
});
}
function processOpenClosedPois(poiMap) {
const idValuesMap = processors.processOpenClosedPois(poiMap);
app.bus.send("poi/setDynamicData", {
plugin: "open-closed-status",
idValuesMap
});
}
async function processDynamicRouting(poiMap) {
const idValuesMap = await processors.processRoutingPois(poiMap);
app.bus.send("poi/setDynamicRouting", { plugin: "routing", idValuesMap });
}
return {
init
};
}
exports.create = create;