const csv = require("csv-parse"); const axios = require("axios"); const { snakeToCamelCase, unzipFile } = require("../../util"); /** * Data available for each passing of a vehicle at a station. * * See also . * @typedef {Object} Passing * @property {string} course Identifier of the overall trip of the same vehicle * from one end of the route to another (unique for the day). * @property {string} stopCode Unused internal stop identifier. * @property {string} stopId Unique network identifier for the station at * which the vehicle will pass (same id as in GTFS). * @property {string} routeShortName Transport line number. * @property {string} tripHeadsign Name of the final stop of this trip. * @property {string} directionId Route identifier inside the line. * @property {string} departureTime Theoretical time at which the * vehicle will depart the stop (HH:MM:SS format). * @property {string} isTheorical (sic) Whether the arrival time is only * a theoretical information. * @property {string} delaySec Number of seconds before the vehicle arrives * at the station. * @property {string} destArCode Unique network identifier for the final * stop of this trip. */ const realtimeEndpoint = "http://data.montpellier3m.fr/node/10732/download"; /** * Fetch real time passings of vehicles across the network. * @yields {{{lastUpdate: number, nextUpdate: number}|Passing}} First value * is an object containing the time of last update and the time of next * update of this information. Next values are informations about each vehicle * passing. */ const fetchRealtime = async function *() { const res = await axios.get(realtimeEndpoint, { responseType: "stream" }); const lastUpdate = new Date(res.headers["last-modified"]).getTime(); const nextUpdate = lastUpdate + 65 * 1000; yield { lastUpdate, nextUpdate }; const parser = res.data.pipe(csv({ delimiter: ";", columns: header => header.map(snakeToCamelCase) })); for await (const passing of parser) { yield passing; } }; exports.fetchRealtime = fetchRealtime; const theoreticalEndpoint = "http://data.montpellier3m.fr/node/10731/download"; /** * Fetch theoretical passings for the current day across the network. * @yields {{{lastUpdate: number, nextUpdate: number}|Passing}} First value * is an object containing the time of last update and the time of next * update of this information. Next values are informations about each vehicle * passing. */ const fetchTheoretical = async function *() { const res = await axios.get(theoreticalEndpoint, { responseType: "stream" }); const lastUpdate = new Date(); if (lastUpdate.getHours() < 4) { lastUpdate.setDate(lastUpdate.getDate() - 1); } lastUpdate.setHours(4); lastUpdate.setMinutes(0); lastUpdate.setSeconds(0); lastUpdate.setMilliseconds(0); const nextUpdate = new Date(lastUpdate); nextUpdate.setDate(nextUpdate.getDate() + 1); yield { lastUpdate: lastUpdate.getTime(), nextUpdate: nextUpdate.getTime() }; const stream = await unzipFile(res.data, "offre_du_jour.csv"); const parser = stream.pipe(csv({ delimiter: ";", columns: header => header.map(snakeToCamelCase) })); for await (const passing of parser) { yield passing; } }; exports.fetchTheoretical = fetchTheoretical;