RELEASE V5.0.0 : Voici les modifications apportées :
-> IMPLÉMENTATION DONNÉES GTFS / GTFS-RT / SIRI LTE SNCF -> RESTRUCTURATION DE L'APP. FONCTIONNALITÉS EN COURS DE DÉVELOPPEMENT : -> REFONTE DU DESIGN DES AFFICHEURS CLASSIQUES -> AMÉLIORATION DES
This commit is contained in:
1 parent
78e0a0ef7b
commit
1729ab4831
1 file changed
+59
-18
+59
-18
@@ -20,6 +20,20 @@ let siriLiteCache = {
|
|||||||
updates: new Map()
|
updates: new Map()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Helper fetch avec timeout pour ne jamais bloquer l'affichage en cas de réseau lent ou de blocage
|
||||||
|
async function fetchWithTimeout(url, options = {}, timeoutMs = 7000) {
|
||||||
|
const controller = new AbortController();
|
||||||
|
const id = setTimeout(() => controller.abort(), timeoutMs);
|
||||||
|
try {
|
||||||
|
const res = await fetch(url, { ...options, signal: controller.signal });
|
||||||
|
clearTimeout(id);
|
||||||
|
return res;
|
||||||
|
} catch (err) {
|
||||||
|
clearTimeout(id);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function cleanNum(n) {
|
function cleanNum(n) {
|
||||||
if (!n) return '';
|
if (!n) return '';
|
||||||
const m = String(n).match(/\d+/);
|
const m = String(n).match(/\d+/);
|
||||||
@@ -39,8 +53,8 @@ async function fetchSiriLiteData() {
|
|||||||
const updatesMap = new Map();
|
const updatesMap = new Map();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(SNCF_SIRI_LITE_TIMETABLE);
|
const res = await fetchWithTimeout(SNCF_SIRI_LITE_TIMETABLE, {}, 8000);
|
||||||
if (res.ok) {
|
if (res && res.ok) {
|
||||||
const xml = await res.text();
|
const xml = await res.text();
|
||||||
const journeys = xml.split('<EstimatedVehicleJourney>');
|
const journeys = xml.split('<EstimatedVehicleJourney>');
|
||||||
|
|
||||||
@@ -123,7 +137,7 @@ async function fetchSiriLiteData() {
|
|||||||
updates: updatesMap
|
updates: updatesMap
|
||||||
};
|
};
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn('[sncfApi] Notice: SIRI-Lite refresh error:', err);
|
console.warn('[sncfApi] Notice: SIRI-Lite refresh error/timeout:', err);
|
||||||
}
|
}
|
||||||
|
|
||||||
return siriLiteCache;
|
return siriLiteCache;
|
||||||
@@ -143,12 +157,12 @@ async function fetchGtfsRealtimeData() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const [rtRes, alertsRes] = await Promise.allSettled([
|
const [rtRes, alertsRes] = await Promise.allSettled([
|
||||||
fetch(SNCF_GTFS_RT_TRIP_UPDATES),
|
fetchWithTimeout(SNCF_GTFS_RT_TRIP_UPDATES, {}, 6000),
|
||||||
fetch(SNCF_GTFS_RT_SERVICE_ALERTS)
|
fetchWithTimeout(SNCF_GTFS_RT_SERVICE_ALERTS, {}, 6000)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 1. Décodage Trip Updates (Retards, Suppressions)
|
// 1. Décodage Trip Updates (Retards, Suppressions)
|
||||||
if (rtRes.status === 'fulfilled' && rtRes.value.ok) {
|
if (rtRes.status === 'fulfilled' && rtRes.value && rtRes.value.ok) {
|
||||||
const buffer = await rtRes.value.arrayBuffer();
|
const buffer = await rtRes.value.arrayBuffer();
|
||||||
const feed = transit_realtime.FeedMessage.decode(new Uint8Array(buffer));
|
const feed = transit_realtime.FeedMessage.decode(new Uint8Array(buffer));
|
||||||
|
|
||||||
@@ -188,7 +202,7 @@ async function fetchGtfsRealtimeData() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2. Décodage Service Alerts (Causes de retards & perturbations)
|
// 2. Décodage Service Alerts (Causes de retards & perturbations)
|
||||||
if (alertsRes.status === 'fulfilled' && alertsRes.value.ok) {
|
if (alertsRes.status === 'fulfilled' && alertsRes.value && alertsRes.value.ok) {
|
||||||
const buffer = await alertsRes.value.arrayBuffer();
|
const buffer = await alertsRes.value.arrayBuffer();
|
||||||
const alertFeed = transit_realtime.FeedMessage.decode(new Uint8Array(buffer));
|
const alertFeed = transit_realtime.FeedMessage.decode(new Uint8Array(buffer));
|
||||||
|
|
||||||
@@ -294,13 +308,29 @@ async function fetchGtfsStationTimetable(uic, mode = 'departs') {
|
|||||||
if (!uic) return null;
|
if (!uic) return null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const publicUrl = (typeof process !== 'undefined' && process.env && process.env.PUBLIC_URL) ? process.env.PUBLIC_URL : '';
|
||||||
|
const stationUrl = `${publicUrl}/data/stations/${uic}.json`;
|
||||||
|
|
||||||
|
// Chargement parallèle tolérant aux pannes réseau / CORS
|
||||||
const [jsonRes, rtData, siriData] = await Promise.all([
|
const [jsonRes, rtData, siriData] = await Promise.all([
|
||||||
fetch(`/data/stations/${uic}.json`),
|
fetch(stationUrl).catch(err => {
|
||||||
fetchGtfsRealtimeData(),
|
console.warn(`[sncfApi] Notice: fetch station ${uic} error:`, err);
|
||||||
fetchSiriLiteData()
|
return null;
|
||||||
|
}),
|
||||||
|
fetchGtfsRealtimeData().catch(err => {
|
||||||
|
console.warn('[sncfApi] Notice: GTFS-RT error:', err);
|
||||||
|
return { updates: new Map(), alerts: [] };
|
||||||
|
}),
|
||||||
|
fetchSiriLiteData().catch(err => {
|
||||||
|
console.warn('[sncfApi] Notice: SIRI-Lite error:', err);
|
||||||
|
return { platforms: new Map(), updates: new Map() };
|
||||||
|
})
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (!jsonRes.ok) return null;
|
if (!jsonRes || !jsonRes.ok) {
|
||||||
|
console.warn(`[sncfApi] Fichier de gare introuvable : ${stationUrl} (statut : ${jsonRes ? jsonRes.status : 'réseau bloqué'})`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const data = await jsonRes.json();
|
const data = await jsonRes.json();
|
||||||
const rawList = mode === 'arrivees' ? data.arrivees : data.departs;
|
const rawList = mode === 'arrivees' ? data.arrivees : data.departs;
|
||||||
@@ -311,19 +341,19 @@ async function fetchGtfsStationTimetable(uic, mode = 'departs') {
|
|||||||
const currentDay = now.getDay(); // 0 = Dimanche, 1 = Lundi, ..., 6 = Samedi
|
const currentDay = now.getDay(); // 0 = Dimanche, 1 = Lundi, ..., 6 = Samedi
|
||||||
const currentYYYYMMDD = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}${String(now.getDate()).padStart(2, '0')}`;
|
const currentYYYYMMDD = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}${String(now.getDate()).padStart(2, '0')}`;
|
||||||
|
|
||||||
// Filtrage complet de circulation GTFS
|
// 1. Filtrage précis par date GTFS (si la date du jour est dans la plage de validité)
|
||||||
const circulatingList = rawList.filter(t => {
|
let circulatingList = rawList.filter(t => {
|
||||||
// 1. Si la date courante figure dans les dates explicites
|
// Si la date courante figure dans les dates explicites
|
||||||
if (Array.isArray(t.dates) && t.dates.length > 0 && t.dates.includes(currentYYYYMMDD)) {
|
if (Array.isArray(t.dates) && t.dates.length > 0 && t.dates.includes(currentYYYYMMDD)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// 2. Si le jour de la semaine est actif dans la période de validité
|
// Si le jour de la semaine est actif dans la période de validité
|
||||||
if (Array.isArray(t.days) && t.days.length > 0 && t.days.includes(currentDay)) {
|
if (Array.isArray(t.days) && t.days.length > 0 && t.days.includes(currentDay)) {
|
||||||
if ((!t.start || currentYYYYMMDD >= t.start) && (!t.end || currentYYYYMMDD <= t.end)) {
|
if ((!t.start || currentYYYYMMDD >= t.start) && (!t.end || currentYYYYMMDD <= t.end)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 3. Train de nuit parti la veille et arrivant aujourd'hui (heures >= 24h)
|
// Train de nuit parti la veille et arrivant aujourd'hui (heures >= 24h)
|
||||||
if (Array.isArray(t.days) && t.days.length > 0) {
|
if (Array.isArray(t.days) && t.days.length > 0) {
|
||||||
const prevDay = (currentDay + 6) % 7;
|
const prevDay = (currentDay + 6) % 7;
|
||||||
const rawTime = mode === 'arrivees' ? (t.arr || t.dep) : (t.dep || t.arr);
|
const rawTime = mode === 'arrivees' ? (t.arr || t.dep) : (t.dep || t.arr);
|
||||||
@@ -333,13 +363,24 @@ async function fetchGtfsStationTimetable(uic, mode = 'departs') {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 4. Si aucune règle n'est renseignée
|
// Si aucune règle n'est renseignée
|
||||||
if (!t.dates?.length && !t.days?.length) return true;
|
if (!t.dates?.length && !t.days?.length) return true;
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 2. Fallback robuste : si la date actuelle est hors calendrier GTFS, filtrer par jour de la semaine
|
||||||
if (circulatingList.length === 0) {
|
if (circulatingList.length === 0) {
|
||||||
return [];
|
circulatingList = rawList.filter(t => {
|
||||||
|
if (Array.isArray(t.days) && t.days.length > 0) {
|
||||||
|
return t.days.includes(currentDay);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Fallback complet : si toujours vide, renvoyer la grille quotidienne complète
|
||||||
|
if (circulatingList.length === 0) {
|
||||||
|
circulatingList = rawList;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper de résolution ultra-robuste de quai par couple (train, gare)
|
// Helper de résolution ultra-robuste de quai par couple (train, gare)
|
||||||
|
|||||||
Reference in new issue
Block a user