Skip to content

Commit

Permalink
add filter to real time APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
Andykmcc committed Apr 26, 2024
1 parent 9e2527f commit 925586b
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 29 deletions.
9 changes: 5 additions & 4 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import fs from 'fs';
import * as dotenv from 'dotenv';
import * as dotenvExpand from 'dotenv-expand';
import { isEmpty } from 'ramda';
import { URL } from 'node:url';

export const PORT = Number(process.env.PORT);
export const PROTOCOL = process.env.PROTOCOL;
Expand Down Expand Up @@ -54,10 +55,10 @@ for (const dotenvFile of dotenvFiles) {
}
}

export const GTFS_REALTIME_TOKEN = process.env.GTFS_REALTIME_TOKEN;
export const GTFS_REALTIME_ALERTS_URL = process.env.GTFS_REALTIME_ALERTS_URL;
export const GTFS_REALTIME_VEHICLE_POSITIONS_URL = process.env.GTFS_REALTIME_VEHICLE_POSITIONS_URL;
export const GTFS_REALTIME_TRIP_UPDATES_URL = process.env.GTFS_REALTIME_TRIP_UPDATES_URL;
export const GTFS_REALTIME_TOKEN = isEmpty(process.env.GTFS_REALTIME_TOKEN) ? null : process.env.GTFS_REALTIME_TOKEN;
export const GTFS_REALTIME_ALERTS_URL = isEmpty(process.env.GTFS_REALTIME_ALERTS_URL) ? null : new URL(process.env.GTFS_REALTIME_ALERTS_URL);
export const GTFS_REALTIME_VEHICLE_POSITIONS_URL = isEmpty(process.env.GTFS_REALTIME_VEHICLE_POSITIONS_URL) ? null : new URL(process.env.GTFS_REALTIME_VEHICLE_POSITIONS_URL);
export const GTFS_REALTIME_TRIP_UPDATES_URL = isEmpty(process.env.GTFS_REALTIME_TRIP_UPDATES_URL) ? null : new URL(process.env.GTFS_REALTIME_TRIP_UPDATES_URL);

// 511.org allows us 60 requests per hour, let's be conservative and
// cache for 3min to make it a maximum of 20.
Expand Down
1 change: 1 addition & 0 deletions src/gtfs-rt/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ async function _getAlertsNoCache() {
const url = new URL(GTFS_REALTIME_ALERTS_URL);
const usp = new URLSearchParams(url.search);
usp.append('api_key', GTFS_REALTIME_TOKEN);
usp.delete('format', 'json');
url.search = usp;

const response = await fetch(url);
Expand Down
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ app.use((req, res, next) => {
app.use('/v1/config', geoConfigRouter);
app.use('/api/v1/config', geoConfigRouter);

app.use('/v1/realtime', realtimeRouter);
app.use('/api/v1/realtime', realtimeRouter);

// generic API path so we don't have a leaky abstraction
Expand Down
1 change: 1 addition & 0 deletions src/lib/logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const logger = pino({
translateTime: true,
},
} : null,
level: process.env.LOG_LEVEL || 'info'
});

export default logger;
99 changes: 74 additions & 25 deletions src/realtime-gtfs/router.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { URL } from 'node:url';
import express from 'express';
import realtimeClient from './client.js';
import cache from '../lib/cache.js';
Expand All @@ -9,13 +8,57 @@ import {
GTFS_REALTIME_TRIP_UPDATES_URL,
} from '../config.js';

const vehiclePositionsUrl = new URL(GTFS_REALTIME_VEHICLE_POSITIONS_URL);
const serviceAlertsUrl = new URL(GTFS_REALTIME_ALERTS_URL);
const tripUpdatesUrl = new URL(GTFS_REALTIME_TRIP_UPDATES_URL);
const vehiclePositionsUrl = GTFS_REALTIME_VEHICLE_POSITIONS_URL;
const serviceAlertsUrl = GTFS_REALTIME_ALERTS_URL;
const tripUpdatesUrl = GTFS_REALTIME_TRIP_UPDATES_URL;

const router = express.Router();

function filterVehiclePositions(tripId, routeId, entities) {
const vehicleFilters = [{
key: 'TripId',
value: tripId
},
{
key: 'RouteId',
value: routeId
}].filter(vehicleFilter => vehicleFilter.value)

return vehicleFilters.reduce((entities, filter) => {
return entities
.filter(entity => entity.Vehicle.Trip)
.filter(entity => entity.Vehicle.Trip[filter.key] === filter.value);
}, entities);
}

function filterTripUpdates(tripId, routeId, entities) {
const vehicleFilters = [{
key: 'TripId',
value: tripId
},
{
key: 'RouteId',
value: routeId
}].filter(vehicleFilter => vehicleFilter.value)

return vehicleFilters.reduce((entities, filter) => {
return entities
.filter(entity => entity.TripUpdate.Trip)
.filter(entity => entity.TripUpdate.Trip[filter.key] === filter.value);
}, entities);
}

async function vehiclePositionsCb (req, res) {
const tripId = req.query.tripid;
const routeId = req.query.routeid;

if (!vehiclePositionsUrl) {
logger.info('env var GTFS_REALTIME_VEHICLE_POSITIONS_URL not found');
res.sendStatus(404);
res.end();
return;
}

// try to get data from cache
try {
const cacheResult = await cache.get('vehiclePositions', {raw: true});
Expand All @@ -25,8 +68,8 @@ async function vehiclePositionsCb (req, res) {
'Cache-Control': 'public, max-age=60',
'Age': Math.floor((cacheResult.expires - Math.floor(new Date().getTime())) / 1000)
});

res.json(cacheResult.value);
res.json(filterVehiclePositions(tripId, routeId, cacheResult.value.Entity));
return;
}
} catch (error) {
Expand Down Expand Up @@ -55,7 +98,7 @@ async function vehiclePositionsCb (req, res) {
'Cache-Control': 'public, max-age=60',
'Age': 0
});
res.json(vehiclePositions);
res.json(filterVehiclePositions(tripId, routeId, vehiclePositions.Entity));
} catch (error) {
if (error.response) {
res.sendStatus(error.response.status);
Expand All @@ -68,6 +111,13 @@ async function vehiclePositionsCb (req, res) {
}

async function serviceAlertsCb (req, res) {
if (!serviceAlertsUrl) {
logger.info('env var GTFS_REALTIME_ALERTS_URL not found');
res.sendStatus(404);
res.end();
return;
}

// try to get data from cache
try {
const cacheResult = await cache.get('serviceAlerts', {raw: true});
Expand All @@ -78,7 +128,7 @@ async function serviceAlertsCb (req, res) {
'Age': Math.floor((cacheResult.expires - Math.floor(new Date().getTime())) / 1000)
});

res.json(cacheResult.value);
res.json(cacheResult.value.Entity);
return;
}
} catch (error) {
Expand Down Expand Up @@ -107,7 +157,7 @@ async function serviceAlertsCb (req, res) {
'Cache-Control': 'public, max-age=60',
'Age': 0
});
res.json(serviceAlerts);
res.json(serviceAlerts.Entity);
} catch (error) {
if (error.response) {
res.sendStatus(error.response.status);
Expand All @@ -120,6 +170,16 @@ async function serviceAlertsCb (req, res) {
}

async function tripUpdatesCb (req, res) {
const tripId = req.query.tripid;
const routeId = req.query.routeid;

if (!tripUpdatesUrl) {
logger.info('env var GTFS_REALTIME_TRIP_UPDATES_URL not found');
res.sendStatus(404);
res.end();
return;
}

// try to get data from cache
try {
const cacheResult = await cache.get('tripUpdates', {raw: true});
Expand All @@ -130,7 +190,7 @@ async function tripUpdatesCb (req, res) {
'Age': Math.floor((cacheResult.expires - Math.floor(new Date().getTime())) / 1000)
});

res.json(cacheResult.value);
res.json(filterTripUpdates(tripId, routeId, cacheResult.value.Entity));
return;
}
} catch (error) {
Expand Down Expand Up @@ -159,7 +219,7 @@ async function tripUpdatesCb (req, res) {
'Cache-Control': 'public, max-age=60',
'Age': 0
});
res.json(tripUpdates);
res.json(filterTripUpdates(tripId, routeId, tripUpdates.Entity));
} catch (error) {
if (error.response) {
res.sendStatus(error.response.status);
Expand All @@ -171,19 +231,8 @@ async function tripUpdatesCb (req, res) {
res.end();
}

// only add vehicle position endpoint if the GTFS_REALTIME_VEHICLE_POSITIONS_URL env var is set
if (vehiclePositionsUrl) {
router.get('/vehiclepositions', vehiclePositionsCb);
}

// only add service alerts endpoint if the GTFS_REALTIME_ALERTS_URL env var is set
if (serviceAlertsUrl) {
router.get('/servicealerts', serviceAlertsCb);
}

// only add trip updates endpoint if the GTFS_REALTIME_TRIP_UPDATES_URL env var is set
if (tripUpdatesUrl) {
router.get('/tripupdates', tripUpdatesCb);
}
router.get('/vehiclepositions', vehiclePositionsCb);
router.get('/servicealerts', serviceAlertsCb);
router.get('/tripupdates', tripUpdatesCb);

export default router;

0 comments on commit 925586b

Please sign in to comment.