UNPKG

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

141 lines (113 loc) 5.27 kB
'use strict'; var Zousan = require('zousan'); var processors = require('./processors.js'); /* This service obtains dynamic POI data from our own backend REST API service. Currently it drives dynamic data for Security Wait Times and Parking Status. Configuration Properties Recognized: urlBase : to override the REST url base. i.e. for alpha use 'https://rest-alpha.locuslabs.com/v1'. You can also reference a local file, such as './testDynamicPois.json' Values defined by 'parking': lotName: Name of the lot for this POI, such as 'East' lotStatus: returns either 'Closed' or 'Open' timeIsReal: If true, the time here is live and valid, else its a default fallback rateDay: Daily Rate expressed in English: '$17 per day' rateHour: Hourly Rate expressed in English: '$5 per hour' timeToTerminal1: Time in walking or by shuttle to Terminal 1 : 'Shuttle 5-7' timeToTerminal2: Time in nwalking or by shuttle to Terminal 2 : 'Walking 5-10' lastUpdated: timestamp of last update (as sent by server) Values defined by 'security' queueTime: Estimated Time in queue (in minutes) : i.e. 45 isTemporarilyClosed: If true, this line is closed - else it is open timeIsReal: If true, the time here is live and valid, else its a default fallback lastUpdated: timestamp of last update (as sent by server) */ let REFRESH_FREQUENCY = 1000 * 30; // every 30 seconds const MARKETPLACE_URL_BASE = 'https://marketplace.locuslabs.com'; const MAX_FETCH_FAILS = 3; // 3 strikes and you're out! const ACCOUNT_ID_HEADER = 'x-account-id'; function create (app, config = {}) { const state = { dynamicDataNotPending: new Zousan() }; const T = app.gt(); // used in testing if (config._overrideRefreshFrequency) REFRESH_FREQUENCY = config._overrideRefreshFrequency; // by returning this dynamicDataLoaded promise, we hold sdkReady event until this is resolved app.bus.on('system/readywhenyouare', () => state.dynamicDataNotPending); 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) // 404 if customer does not have dynamic POIs return response.json() .then(({ data }) => processDynamicPois(data)) .then(() => { fetchSuccessCount++; }) .catch(console.error) else { console.warn('dynamicPois: fetch response status not ok', response); fetchFailuresCount++; // Don't keep trying after multiple fails unless past success is at least 50% if (fetchFailuresCount >= MAX_FETCH_FAILS && fetchFailuresCount > fetchSuccessCount) clearInterval(fetchIntervalHandle); } }; return updateFromAPI() .then(() => { fetchIntervalHandle = setInterval(updateFromAPI, REFRESH_FREQUENCY); if (typeof fetchIntervalHandle.unref === 'function') fetchIntervalHandle.unref(); // Node only - do not keep-alive Lambda or other short-term environments }) .finally(() => state.dynamicDataNotPending.resolve(true)) // even in case of failure, we don't want to hold up the UI }; async function processDynamicPois (pois) { processParkingPOIS(pois); processOpenClosedPois(pois); processSecurityWaitTimes(pois); processDynamicRouting(pois); } 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 }; /* API response: https://gitlab.com/locuslabs/core-data-team/json-schemas/-/blob/develop/src/api-marketplace/dynamic-queue-data.json */ async function processSecurityWaitTimes (poiMap) { const idValuesMap = processors.processSecurityWaitTimes(poiMap); app.bus.send('poi/setDynamicData', { plugin: 'security', idValuesMap }); const labels = await getPOILabels(Object.keys(idValuesMap)); // get a map of labels for the POIs - used in wait time labeling 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;