tracktracker/back/data/realtime.js

178 lines
5.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const axios = require('axios');
const csv = require('csv-parse');
const network = require('./network');
const {TAM_REALTIME} = require('./endpoints');
const sortByFirstKey = (a, b) => a[0] - b[0];
const fetchRealtime = () => new Promise((res, rej) =>
{
const stream = axios.get(TAM_REALTIME, {
responseType: 'stream'
}).then(stream =>
{
const parser = csv({
delimiter: ';',
});
const courses = {};
stream.pipe(parser);
stream.on('readable', () =>
{
let row;
while (row = stream.read())
{
if (row.length === 0 || row[0] === 'course')
{
// Ignore les lignes invalides et len-tête
continue;
}
const course = row[0];
const stopRef = row[2];
const lineRef = row[4];
const eta = row[9];
const destinationRef = row[10];
if (!(course in courses))
{
courses[course] = {
lineRef,
destinationRef,
stops: [],
};
}
courses[course].stops.push([parseInt(eta, 10), stopRef]);
courses[course].stops.sort(sortByFirstKey);
}
});
stream.on('end', () => res(courses));
stream.on('error', err => rej(err));
});
});
const updateVehicles = async (lines, vehicles) =>
{
const courses = await fetchRealtime();
const currentTime = Math.floor(Date.now() / 1000);
for (let [courseRef, course] of Object.entries(courses))
{
if (course.lineRef in lines)
{
if (!(courseRef in vehicles))
{
// New vehicle: identify which route it pertains to
const line = lines[course.lineRef];
let routeIndex = null;
for (let [index, route] of Object.entries(line.routes))
{
const destRef = route.stops[route.stops.length - 1].ref;
if (destRef === course.destinationRef)
{
routeIndex = index;
}
}
if (routeIndex !== null)
{
const route = line.routes[routeIndex];
// Convert ETAs to absolute times
const nextStops = course.stops.map(([eta, ref]) => [
eta + currentTime,
ref
]);
// Convert stop refs to indices
const stopIndices = course.stops.map(([eta, ref]) => [
eta,
]);
// Find the preceding stop from which the vehicle is coming
const arrivingStop = stopIndices[0][1];
const arrivingStopIndex = route.stops.findIndex(
stop => stop.ref === arrivingStop
);
const leavingStop = arrivingStopIndex === 0
? route.stops[0]
: route.stops[arrivingStopIndex - 1];
if (nextStop === 0)
{
// Vehicle at starting point
vehicles[courseRef] = {
lineRef: course.lineRef,
stopRef
stopIndex: 0,
nextStops: stopIndices,
distance: 0,
speed: 0,
};
}
else
{
// Vehicle in transit between two stops
vehicles[courseRef] = {
lineRef: course.lineRef,
routeIndex,
stopIndex: nextStop - 1,
nextStops: stopIndices,
distance: 0,
speed: route.distances[nextStop - 1] / eta,
};
}
}
}
else
{
// Existing vehicle: update information
const vehicle = vehicles[courseRef];
const line = lines[vehicle.lineRef];
const route = line.routes[vehicle.routeIndex];
// Convert stop refs to indices
const stopIndices = course.stops.map(([eta, ref]) => [
eta,
route.stops.findIndex(stop => stop.ref === ref),
]);
console.log(stopIndices);
console.log(vehicle);
console.log(course);
console.log('---');
}
}
}
};
const sleep = time => new Promise(res => setTimeout(res, time));
const updateLoop = async (lines, vehicles = {}) =>
{
await updateVehicles(lines, vehicles);
await sleep(30000);
return updateLoop(lines, vehicles);
};
(async () =>
{
const lines = {'1': await network.fetchLineData('1')};
updateLoop(lines);
// console.log(require('util').inspect(vehicles, true, 10));
})();