diff --git a/src/routers/v1/MultiRouteRouter.js b/src/routers/v1/MultiRouteRouter.js index e8eeeb95..8f98ee37 100644 --- a/src/routers/v1/MultiRouteRouter.js +++ b/src/routers/v1/MultiRouteRouter.js @@ -2,10 +2,11 @@ import type Request from 'express'; import AnalyticsUtils from '../../utils/AnalyticsUtils'; import ApplicationRouter from '../../appdev/ApplicationRouter'; -import Constants from '../../utils/Constants'; import LogUtils from '../../utils/LogUtils'; import RouteUtils from '../../utils/RouteUtils'; +const CURRENT_LOCATION = 'Current Location'; + /** * Router object that returns an array of the best available route for each * destination, specified from a single start destination. @@ -38,7 +39,7 @@ class MultiRouteRouter extends ApplicationRouter> { // get array of routes for each destination const multiRoutes = destinationNames.map((destinationName, index) => RouteUtils.getRoutes( - Constants.CURRENT_LOCATION, + CURRENT_LOCATION, destinationName, end[index], start, diff --git a/src/routers/v1/PlacesAutocompleteRouter.js b/src/routers/v1/PlacesAutocompleteRouter.js index 8203f5f2..affefef0 100644 --- a/src/routers/v1/PlacesAutocompleteRouter.js +++ b/src/routers/v1/PlacesAutocompleteRouter.js @@ -1,10 +1,13 @@ // @flow import LRU from 'lru-cache'; import ApplicationRouter from '../../appdev/ApplicationRouter'; -import Constants from '../../utils/Constants'; import RequestUtils from '../../utils/RequestUtils'; -const cache = LRU(Constants.AUTOCOMPLETE_CACHE_OPTIONS); +const cacheOptions = { + max: 10000, + maxAge: 1000 * 60 * 60 * 24 * 5, +}; +const cache = LRU(cacheOptions); class PlacesAutocompleteRouter extends ApplicationRouter { constructor() { @@ -30,12 +33,12 @@ class PlacesAutocompleteRouter extends ApplicationRouter { // not in cache const options = { method: 'GET', - url: Constants.GOOGLE_AUTOCOMPLETE_URL, + url: 'https://maps.googleapis.com/maps/api/place/autocomplete/json', qs: { input: query, key: process.env.PLACES_KEY, - location: Constants.GOOGLE_PLACE_LOCATION, - radius: Constants.AUTOCOMPLETE_RADIUS, + location: '42.4440,-76.5019', + radius: 24140, strictbounds: '', }, }; diff --git a/src/routers/v1/SearchRouter.js b/src/routers/v1/SearchRouter.js index 66c079fe..b2d6c806 100644 --- a/src/routers/v1/SearchRouter.js +++ b/src/routers/v1/SearchRouter.js @@ -6,7 +6,13 @@ import RequestUtils from '../../utils/RequestUtils'; import SearchUtils from '../../utils/SearchUtils'; import Constants from '../../utils/Constants'; -const queryToPredictionsCache = LRU(Constants.QUERY_PREDICTIONS_CACHE_OPTIONS); +const queryToPredictionsCacheOptions = { + max: 10000, // Maximum size of cache + maxAge: 1000 * 60 * 60 * 24 * 5, // Maximum age in milliseconds +}; +const queryToPredictionsCache = LRU(queryToPredictionsCacheOptions); +const GOOGLE_PLACE = 'googlePlace'; +const GOOGLE_PLACE_LOCATION = '42.4440,-76.5019'; class SearchRouter extends ApplicationRouter> { constructor() { @@ -33,11 +39,11 @@ class SearchRouter extends ApplicationRouter> { // not in cache const options = { ...Constants.GET_OPTIONS, - url: Constants.GOOGLE_AUTOCOMPLETE_URL, + url: 'https://maps.googleapis.com/maps/api/place/autocomplete/json', qs: { input: query, key: process.env.PLACES_KEY, - location: Constants.GOOGLE_PLACE_LOCATION, + location: GOOGLE_PLACE_LOCATION, radius: 24140, strictbounds: '', }, @@ -53,7 +59,7 @@ class SearchRouter extends ApplicationRouter> { const googlePredictions = await Promise.all(predictions.map(async (p): Promise => { const placeIDCoords = await SearchUtils.getCoordsForPlaceID(p.place_id); return { - type: Constants.GOOGLE_PLACE, + type: GOOGLE_PLACE, detail: p.structured_formatting.secondary_text, name: p.structured_formatting.main_text, placeID: p.place_id, diff --git a/src/utils/AllStopUtils.js b/src/utils/AllStopUtils.js index 4f941f04..ad8faf92 100644 --- a/src/utils/AllStopUtils.js +++ b/src/utils/AllStopUtils.js @@ -3,8 +3,14 @@ import Constants from './Constants'; import { PYTHON_APP } from './EnvUtils'; import RequestUtils from './RequestUtils'; -// TODO: investigate why importing from Constants.js results in failure of getting routes +const SEC_IN_MS = 1000; +const MIN_IN_MS = SEC_IN_MS * 60; +const HOUR_IN_MS = MIN_IN_MS * 60; +const DEG_EXACT_PRECISION = 6; // 6 degrees of precision is about a 111 mm, is exact point const DEG_EQ_PRECISION = 5; // 5 degrees of precision is about a 1.1 meters, is a stop +const DEG_NEARBY_PRECISION = 4; // 4 degrees of precision is about 11 meters, stop nearby +const DEG_WALK_PRECISION = 3; // 3 degrees of precision is about 111 meters, stop walkable +const DEG_KM_PRECISION = 2; // 3 degrees of precision is about 1 km, stop barely walkable /** * Used for finding stops at or nearby a point @@ -49,8 +55,8 @@ const updateFunc = async () => { RequestUtils.updateObjectOnInterval( updateFunc, - Constants.HOUR_IN_MS, - Constants.MIN_IN_MS, + HOUR_IN_MS, + MIN_IN_MS, null, ); @@ -76,10 +82,7 @@ function fetchPrecisionMaps() { * @returns {Promise} */ async function getPrecisionMap(degreesPrecision: ?number = DEG_EQ_PRECISION) { - if ( - degreesPrecision < Constants.DEG_MIN_PRECISION - || degreesPrecision > Constants.DEG_MAX_PRECISION - ) { + if (degreesPrecision < 1 || degreesPrecision > 6) { return null; } const stops = await fetchAllStops(); @@ -105,7 +108,7 @@ async function getPrecisionMap(degreesPrecision: ?number = DEG_EQ_PRECISION) { * @param degreesPrecision * @returns {Promise} */ -async function isStopsWithinPrecision(point: Object, degreesPrecision: ?number = Constants.DEG_EQ_PRECISION) { +async function isStopsWithinPrecision(point: Object, degreesPrecision: ?number = DEG_EQ_PRECISION) { const stops = await getPrecisionMap(degreesPrecision); const lat = parseFloat(point.lat).toFixed(degreesPrecision); let found = stops[lat]; // found stop(s) at lat @@ -133,6 +136,11 @@ function isStop(point: Object) { } export default { + DEG_EQ_PRECISION, + DEG_EXACT_PRECISION, + DEG_KM_PRECISION, + DEG_NEARBY_PRECISION, + DEG_WALK_PRECISION, fetchAllStops, isStop, isStopsWithinPrecision, diff --git a/src/utils/AnalyticsUtils.js b/src/utils/AnalyticsUtils.js index 803899bb..6d8c6277 100644 --- a/src/utils/AnalyticsUtils.js +++ b/src/utils/AnalyticsUtils.js @@ -1,10 +1,12 @@ // @flow import crypto from 'crypto'; import LRU from 'lru-cache'; -import Constants from './Constants'; import LogUtils from './LogUtils'; -const routesCalculationsCache = LRU(Constants.ROUTES_CALC_CACHE_OPTIONS); +const routesCalculationsCache = LRU({ + max: 1000, // max 1000 routes in storage + maxAge: 1000 * 60 * 15, // max age 15 minutes +}); function getUniqueId(numBytes: ?number = 10) { return crypto.randomBytes(numBytes).toString('hex'); diff --git a/src/utils/Constants.js b/src/utils/Constants.js index fa416092..a7e706fc 100644 --- a/src/utils/Constants.js +++ b/src/utils/Constants.js @@ -1,65 +1,5 @@ -/* Cache constants */ -// A cache containing Google Autocomplete results -const AUTOCOMPLETE_CACHE_OPTIONS = { - max: 10000, // Max 10000 autocomplete results - maxAge: 1000 * 60 * 60 * 24 * 5, // Max age in 5 days -}; - -// A cache containing saved routes IDs to routes -const ROUTES_CALC_CACHE_OPTIONS = { - max: 1000, // Max 1000 routes - maxAge: 1000 * 60 * 15, // Max age in 15 minutes -}; - -// A cache mapping a /search's request query string to its Google autocomplete predictions -const QUERY_PREDICTIONS_CACHE_OPTIONS = { - max: 10000, // Max 1000 predictions - maxAge: 1000 * 60 * 60 * 24 * 5, // Max age in 5 days -}; - -/* Count constants */ -// The minimum fuzzy string matching ratio that a word has to match a target word for /search -const MIN_FUZZ_RATIO = 75; - -/* Delay Buffer constants */ -// A buffer to account for routes in past 20 minutes with delays -const FIRST_DELAY_BUFFER_IN_MINUTES = 20; -// An additional buffer to account for time needed to walk from current location to bus stop -const SECOND_DELAY_BUFFER_IN_MINUTES = 40; - -/* Distance & Speed constants */ -// > 3.0 suggests getting off bus earlier and walk half a mile instead of waiting longer -const MAX_WALK_DIST_PER_LEG = 2000; -// The distance (in meters) within which to return Google place results for autocomplete. -const AUTOCOMPLETE_RADIUS = 24140; -const WALK_SPEED = 3.0; - -/* Degrees Precision constants */ -const DEG_MIN_PRECISION = 1; -const DEG_KM_PRECISION = 2; // 2 degrees of precision is about 1 km, a barely walkable stop -const DEG_WALK_PRECISION = 3; // 3 degrees of precision is about 111 meters, a walkable stop -const DEG_NEARBY_PRECISION = 4; // 4 degrees of precision is about 11 meters, a nearby stop -const DEG_EQ_PRECISION = 5; // 5 degrees of precision is about 1.1 meters, a stop -const DEG_EXACT_PRECISION = 6; // 6 degrees of precision is about 111 mm, an exact point -const DEG_MAX_PRECISION = 6; - -/* String & URL constants */ -const BUS_STOP = 'busStop'; -const CURRENT_LOCATION = 'Current Location'; -const GOOGLE_AUTOCOMPLETE_URL = 'https://maps.googleapis.com/maps/api/place/autocomplete/json'; -const GOOGLE_PLACE = 'googlePlace'; -const GOOGLE_PLACE_LOCATION = '42.4440,-76.5019'; -const GOOGLE_PLACES_URL = 'https://maps.googleapis.com/maps/api/place/details/json'; -const TOKEN_URL = 'https://gateway.api.cloud.wso2.com:443/token'; - -/* Time constants */ -const SEC_IN_MS = 1000; -const MIN_IN_MS = SEC_IN_MS * 60; -const HOUR_IN_MS = MIN_IN_MS * 60; const THREE_SEC_IN_MS = 3000; -const TOKEN_EXPIRATION_WINDOW_IN_MS = 500; -/* Request constants */ const GET_OPTIONS = { method: 'GET', headers: { 'Cache-Control': 'no-cache' }, @@ -67,32 +7,5 @@ const GET_OPTIONS = { }; export default { - AUTOCOMPLETE_CACHE_OPTIONS, - BUS_STOP, - CURRENT_LOCATION, - DEG_EQ_PRECISION, - DEG_EXACT_PRECISION, - DEG_KM_PRECISION, - DEG_MAX_PRECISION, - DEG_MIN_PRECISION, - DEG_NEARBY_PRECISION, - DEG_WALK_PRECISION, - FIRST_DELAY_BUFFER_IN_MINUTES, GET_OPTIONS, - GOOGLE_AUTOCOMPLETE_URL, - GOOGLE_PLACE, - GOOGLE_PLACE_LOCATION, - GOOGLE_PLACES_URL, - HOUR_IN_MS, - MIN_FUZZ_RATIO, - MAX_WALK_DIST_PER_LEG, - QUERY_PREDICTIONS_CACHE_OPTIONS, - AUTOCOMPLETE_RADIUS, - ROUTES_CALC_CACHE_OPTIONS, - SEC_IN_MS, - SECOND_DELAY_BUFFER_IN_MINUTES, - THREE_SEC_IN_MS, - TOKEN_EXPIRATION_WINDOW_IN_MS, - TOKEN_URL, - WALK_SPEED, }; diff --git a/src/utils/GraphhopperUtils.js b/src/utils/GraphhopperUtils.js index 8e55fdbd..c5b63f83 100644 --- a/src/utils/GraphhopperUtils.js +++ b/src/utils/GraphhopperUtils.js @@ -2,10 +2,15 @@ import { GHOPPER_BUS, GHOPPER_WALKING, } from './EnvUtils'; -import Constants from './Constants'; import LogUtils from './LogUtils'; import RequestUtils from './RequestUtils'; +// buffer to account for routes in past 20 minutes with delays +const FIRST_DELAY_BUFFER_IN_MINUTES = 20; + +// additional buffer to account for time needed to walk from current location to bus stop +const SECOND_DELAY_BUFFER_IN_MINUTES = 40; + /** * https://graphhopper.com/api/1/docs/routing/#output * @param end @@ -23,9 +28,9 @@ const getGraphhopperBusParams = ( 'ch.disable': true, 'pt.arrive_by': arriveBy, 'pt.earliest_departure_time': getDepartureTimeDate(departureTimeQuery, arriveBy, delayBufferMinutes), - 'pt.max_walk_distance_per_leg': Constants.MAX_WALK_DIST_PER_LEG, + 'pt.max_walk_distance_per_leg': 2000, 'pt.profile': true, - 'pt.walk_speed': Constants.WALK_SPEED, + 'pt.walk_speed': 3.0, // > 3.0 suggests getting off bus earlier and walk half a mile instead of waiting longer elevation: false, point: [start, end], points_encoded: false, @@ -215,7 +220,7 @@ async function fetchRoutes(end: string, start: string, departureTimeDateNow: str start, departureTimeDateNow, isArriveByQuery, - Constants.FIRST_DELAY_BUFFER_IN_MINUTES, + FIRST_DELAY_BUFFER_IN_MINUTES, sharedOptions, ); @@ -225,7 +230,7 @@ async function fetchRoutes(end: string, start: string, departureTimeDateNow: str start, departureTimeDateNow, isArriveByQuery, - Constants.SECOND_DELAY_BUFFER_IN_MINUTES, + SECOND_DELAY_BUFFER_IN_MINUTES, sharedOptions, ); @@ -270,13 +275,7 @@ async function fetchRoutes(end: string, start: string, departureTimeDateNow: str } else { LogUtils.log( busRouteBufferedFirstRequest && busRouteBufferedFirstRequest.body, - getGraphhopperBusParams( - end, - start, - departureTimeDateNow, - isArriveByQuery, - Constants.FIRST_DELAY_BUFFER_IN_MINUTES, - ), + getGraphhopperBusParams(end, start, departureTimeDateNow, isArriveByQuery, FIRST_DELAY_BUFFER_IN_MINUTES), `Routing failed: ${GHOPPER_BUS || 'undefined graphhopper bus env'}`, ); } @@ -287,13 +286,7 @@ async function fetchRoutes(end: string, start: string, departureTimeDateNow: str } else { LogUtils.log( busRouteBufferedSecondRequest && busRouteBufferedSecondRequest.body, - getGraphhopperBusParams( - end, - start, - departureTimeDateNow, - isArriveByQuery, - Constants.SECOND_DELAY_BUFFER_IN_MINUTES, - ), + getGraphhopperBusParams(end, start, departureTimeDateNow, isArriveByQuery, SECOND_DELAY_BUFFER_IN_MINUTES), `Routing failed: ${GHOPPER_BUS || 'undefined graphhopper bus env'}`, ); } diff --git a/src/utils/TokenUtils.js b/src/utils/TokenUtils.js index 3f74b2ea..d5c517f2 100644 --- a/src/utils/TokenUtils.js +++ b/src/utils/TokenUtils.js @@ -1,10 +1,10 @@ // @flow import request from 'request'; -import Constants from './Constants'; import { TOKEN } from './EnvUtils'; import LogUtils from './LogUtils'; +const TOKEN_EXPIRATION_WINDOW_IN_MS = 500; let credentials = { basic_token: TOKEN, access_token: '', expiration_date: '' }; function isAccessTokenExpired(): boolean { @@ -14,7 +14,7 @@ function isAccessTokenExpired(): boolean { const currentTime = new Date().getTime(); const tokenExpirationTime = (new Date(credentials.expiration_date)).getTime(); - return tokenExpirationTime - currentTime < Constants.TOKEN_EXPIRATION_WINDOW_IN_MS; + return tokenExpirationTime - currentTime < TOKEN_EXPIRATION_WINDOW_IN_MS; } function fetchAccessToken(): void { @@ -25,10 +25,11 @@ function fetchAccessToken(): void { const basicAuthHeader = `Basic ${credentials.basic_token}`; const options = { method: 'POST', - url: Constants.TOKEN_URL, + url: 'https://gateway.api.cloud.wso2.com:443/token', qs: { grant_type: 'client_credentials' }, headers: { Authorization: basicAuthHeader, + 'Postman-Token': '42201611-965d-4832-a4c5-060ad3ff3b83', 'Cache-Control': 'no-cache', }, };