const tam = require('./sources/tam'); const util = require('../util'); /** * Comparison function between two stop passings. * * @param passing1 First stop passing. * @param passing2 Second stop passing. * @return Negative value if passing1 is sooner than passing2, positive * otherwise, zero if they occur at the same time. */ const passingCompare = ({arrivalTime: time1}, {arrivalTime: time2}) => ( time1 - time2 ); // 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, sorted by increasing * arrival time, containing both the stop identifier (`stopId`) and the * expected arrival timestamp (`arrivalTime`). * * @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)) { // End of courses information stream. Sort next stops by increasing // arrival time in each course then save result in memory cache for (let course of Object.values(courses)) { course.nextPassings.sort(passingCompare); } 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.push({stopId, arrivalTime}); } }); }); exports.getCourses = getCourses;