11const express = require ( 'express' ) ;
22const { Pool } = require ( 'pg' ) ;
33const path = require ( 'path' ) ;
4+ const fs = require ( 'fs' ) ;
45
56const app = express ( ) ;
67const PORT = process . env . PORT || 3000 ;
@@ -20,6 +21,43 @@ const TRAIN_TYPES = {
2021 20 : 'Alaris' , 25 : 'AVE TGV' , 28 : 'AVLO' , 29 : 'Trenhotel Lusitania'
2122} ;
2223
24+ // ── Mapa de estaciones ───────────────────────────────────────────────────────
25+
26+ let stationMap = { } ;
27+
28+ function loadStationMap ( ) {
29+ try {
30+ const raw = fs . readFileSync ( path . join ( __dirname , 'estaciones.geojson' ) , 'utf8' ) ;
31+ const geojson = JSON . parse ( raw ) ;
32+ if ( geojson . features ) {
33+ geojson . features . forEach ( f => {
34+ const code = f . properties . CODIGO ;
35+ const name = f . properties . NOMBRE ;
36+ if ( code && name ) stationMap [ code ] = name ;
37+ } ) ;
38+ }
39+ console . log ( `✅ ${ Object . keys ( stationMap ) . length } estaciones cargadas` ) ;
40+ } catch ( err ) {
41+ console . warn ( '⚠️ No se pudo cargar estaciones.geojson:' , err . message ) ;
42+ }
43+ }
44+
45+ /** Igual que getCorridorName() en app.js — resuelve códigos LMD/etc. a nombres legibles */
46+ function resolveCorridorName ( train ) {
47+ const corridor = train . desCorridor || '' ;
48+ if ( ! corridor || / ^ [ A - Z ] { 2 , 3 } \d + / . test ( corridor ) ) {
49+ const originCode = parseInt ( train . codOrigen ) ;
50+ const destCode = parseInt ( train . codDestino ) ;
51+ if ( originCode && destCode ) {
52+ const originName = stationMap [ originCode ] ;
53+ const destName = stationMap [ destCode ] ;
54+ if ( originName && destName ) return `${ originName } - ${ destName } ` ;
55+ }
56+ return corridor || `${ train . codOrigen || '' } -${ train . codDestino || '' } ` ;
57+ }
58+ return corridor ;
59+ }
60+
2361// Estado del colector (para el endpoint /api/collector/status)
2462const collectorStatus = {
2563 lastRun : null ,
@@ -60,6 +98,42 @@ async function initDB() {
6098 console . log ( '✅ Base de datos lista' ) ;
6199}
62100
101+ /** Corrige registros existentes cuyo corredor es un código (ej. LMD71234) */
102+ async function fixExistingCorridors ( ) {
103+ if ( Object . keys ( stationMap ) . length === 0 ) return ;
104+
105+ const res = await pool . query ( `
106+ SELECT id, origin_code, dest_code
107+ FROM trip_records
108+ WHERE corridor ~ '^[A-Z]{2,3}[0-9]+'
109+ ` ) ;
110+ if ( res . rowCount === 0 ) return ;
111+
112+ const client = await pool . connect ( ) ;
113+ let fixed = 0 ;
114+ try {
115+ await client . query ( 'BEGIN' ) ;
116+ for ( const row of res . rows ) {
117+ const originName = stationMap [ row . origin_code ] ;
118+ const destName = stationMap [ row . dest_code ] ;
119+ if ( originName && destName ) {
120+ await client . query (
121+ 'UPDATE trip_records SET corridor = $1 WHERE id = $2' ,
122+ [ `${ originName } - ${ destName } ` , row . id ]
123+ ) ;
124+ fixed ++ ;
125+ }
126+ }
127+ await client . query ( 'COMMIT' ) ;
128+ if ( fixed > 0 ) console . log ( `✅ ${ fixed } corredores corregidos en BD` ) ;
129+ } catch ( err ) {
130+ await client . query ( 'ROLLBACK' ) ;
131+ console . error ( '❌ Error al corregir corredores:' , err . message ) ;
132+ } finally {
133+ client . release ( ) ;
134+ }
135+ }
136+
63137// ── Colector de datos ────────────────────────────────────────────────────────
64138
65139/**
@@ -110,14 +184,15 @@ async function collectData() {
110184 const delay = parseInt ( train . ultRetraso || 0 ) ;
111185 const id = `${ trainId } _${ dateStr } ` ;
112186 const trainType = TRAIN_TYPES [ train . codProduct ] || 'Desconocido' ;
113- const corridor = train . desCorridor || ` ${ train . codOrigen || '' } - ${ train . codDestino || '' } ` ;
187+ const corridor = resolveCorridorName ( train ) ;
114188
115189 await client . query ( `
116190 INSERT INTO trip_records
117191 (id, train_id, train_type, corridor, origin_code, dest_code,
118192 date, day_of_week, first_seen, last_seen, max_delay, final_delay, was_delayed)
119193 VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13)
120194 ON CONFLICT (id) DO UPDATE SET
195+ corridor = EXCLUDED.corridor,
121196 last_seen = GREATEST(trip_records.last_seen, EXCLUDED.last_seen),
122197 first_seen = LEAST (trip_records.first_seen, EXCLUDED.first_seen),
123198 max_delay = GREATEST(trip_records.max_delay, EXCLUDED.max_delay),
@@ -432,8 +507,13 @@ async function pruneOldData() {
432507
433508// ── Arranque ─────────────────────────────────────────────────────────────────
434509
510+ loadStationMap ( ) ;
511+
435512initDB ( )
436513 . then ( async ( ) => {
514+ // Corregir corredores mal almacenados en BD
515+ await fixExistingCorridors ( ) ;
516+
437517 // Primera recolección inmediata
438518 await collectData ( ) ;
439519
0 commit comments