const tam = require('./sources/tam'); const util = require('../util'); const network = require('./network.json'); // Time at which the course data needs to be updated next let nextUpdate = null; // Current information about courses let currentCourses = null; /** * Fetch real-time information about active courses in the TaM network. * * New data will only be fetched from the TaM server once every minute, * otherwise pulling from the in-memory cache. * * The following information is provided for each active course: * * - `id`: Unique identifier for the course. * - `line`: Line number. * - `finalStop`: The final stop to which the course is headed. * - `nextPassings`: Next passings of the vehicle, as a dictionary associating * each next stop to the passing timestamp. * * @return Mapping from active course IDs to information about each course. */ const getCourses = () => new Promise((res, rej) => { if (nextUpdate !== null && Date.now() < nextUpdate) { res(currentCourses); return; } const courses = {}; let lastUpdate = null; tam.fetchRealtime((err, entry) => { if (err) { rej(err); return; } if (!util.isObject(entry)) { // Filter courses to only keep those referring to known data for (let courseId of Object.keys(courses)) { const course = courses[courseId]; if (!(course.line in network.lines)) { delete courses[courseId]; } else { for (let stopId of Object.keys(course.nextPassings)) { if (!(stopId in network.stops)) { delete courses[courseId]; break; } } } } currentCourses = courses; res(currentCourses); return; } if ('lastUpdate' in entry) { // Metadata header lastUpdate = entry.lastUpdate; nextUpdate = entry.nextUpdate; return; } const { course: id, routeShortName: line, stopId, destArCode: finalStop, } = entry; const arrivalTime = lastUpdate + parseInt(entry.delaySec, 10) * 1000; if (!(id in courses)) { courses[id] = { id, line, finalStop, nextPassings: {[stopId]: arrivalTime}, }; } else { courses[id].nextPassings[stopId] = arrivalTime; } }); }); exports.getCourses = getCourses;