summaryrefslogtreecommitdiff
path: root/lib/Travelynx/Model
diff options
context:
space:
mode:
authorBirte Kristina Friesel <derf@finalrewind.org>2025-06-15 08:23:48 +0200
committerBirte Kristina Friesel <derf@finalrewind.org>2025-06-15 08:23:51 +0200
commitc250a2f2c7968966014315f76b25109b83c041ed (patch)
tree3c6ee328e7e67beadeac44d9458a048fe3e0b473 /lib/Travelynx/Model
parentf1da50f9f18f0a2a5fd202daff4b6f0b517f35e0 (diff)
Add experimental EFA support
Squashed commit of the following: commit b7457791ab7ab4859ebf4a5ce173e1aaeed4c7fb Author: Birte Kristina Friesel <derf@finalrewind.org> Date: Sun Jun 15 08:18:46 2025 +0200 changelog commit 7f3d61066195cfc3c83a8fc1b2fc3743e7e6171c Author: Birte Kristina Friesel <derf@finalrewind.org> Date: Sat Jun 14 19:55:51 2025 +0200 Mark EFA backends as experimental for now For instance, VRR has very interesting issues when checking into departures that do not have real-time data yet. commit 3370c0f6c25bd6b02cc4d56e9a3aba2a66d1151a Author: Birte Kristina Friesel <derf@finalrewind.org> Date: Sat Jun 14 19:49:48 2025 +0200 InTransit: remove debug output commit deb5444fa2965228b537e86fce862436ef2e6e19 Author: Birte Kristina Friesel <derf@finalrewind.org> Date: Sat Jun 14 19:12:44 2025 +0200 frontend js for checked-in view: never show fractional delays commit d47ff9615b551bbd844a799be7717e9e74a04266 Author: Birte Kristina Friesel <derf@finalrewind.org> Date: Sat Jun 14 19:12:31 2025 +0200 worker: add EFA support commit 3a955c0105bf13d040a821e2c87a19694202cde6 Author: Birte Kristina Friesel <derf@finalrewind.org> Date: Sat Jun 14 17:48:46 2025 +0200 EFA: checkin support worker support and cancellations are still missing commit 19dea1ad13029d19cba38e7d1338718149c139fb Author: Birte Kristina Friesel <derf@finalrewind.org> Date: Sat Jun 14 14:32:59 2025 +0200 actions.js: pass on efa parameter commit 8f18ff2c8f9f906a387dbe16d372e1c4b4a6f259 Author: Birte Kristina Friesel <derf@finalrewind.org> Date: Sat Jun 14 14:32:48 2025 +0200 EFA: implement geolocation lookup commit bce1139bab9aab167cdab910fa86085529d45b80 Author: Birte Kristina Friesel <derf@finalrewind.org> Date: Sat Jun 14 14:32:21 2025 +0200 EFA: ->id is no longer supported, use ->id_num commit e4397e6b1538ddfa71da9839d6011a73fadc528f Author: Birte Kristina Friesel <derf@finalrewind.org> Date: Mon Jun 9 20:34:22 2025 +0200 ... derp commit e0c4cbf862a8f5a7bca0b1aceab3760af94093e9 Author: Birte Kristina Friesel <derf@finalrewind.org> Date: Mon Jun 9 18:28:35 2025 +0200 database: it's dbris, not ris commit bfb1e834ce6c3171011dc20b32117065960b8771 Merge: 42f9a00 f1da50f Author: Birte Kristina Friesel <derf@finalrewind.org> Date: Mon Jun 9 18:20:51 2025 +0200 Merge branch 'main' into efa-support commit 42f9a00d98dbd675234c05b3e25c3e722cfdd7ba Author: Birte Kristina Friesel <derf@finalrewind.org> Date: Wed Jan 8 18:11:28 2025 +0100 EFA support (WiP)
Diffstat (limited to 'lib/Travelynx/Model')
-rw-r--r--lib/Travelynx/Model/InTransit.pm171
-rwxr-xr-xlib/Travelynx/Model/Journeys.pm5
-rw-r--r--lib/Travelynx/Model/Stations.pm63
-rw-r--r--lib/Travelynx/Model/Users.pm3
4 files changed, 224 insertions, 18 deletions
diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm
index cc943b3..470b45d 100644
--- a/lib/Travelynx/Model/InTransit.pm
+++ b/lib/Travelynx/Model/InTransit.pm
@@ -110,8 +110,6 @@ sub add {
my $now = DateTime->now( time_zone => 'Europe/Berlin' );
if ($train) {
-
- # IRIS
$db->insert(
'in_transit',
{
@@ -142,9 +140,60 @@ sub add {
}
);
}
- elsif ( $journey and $stop and $journey->can('product') ) {
-
- # HAFAS
+ elsif ( $journey
+ and $stop
+ and ref($journey) eq 'Travel::Status::DE::EFA::Trip' )
+ {
+ my @route;
+ for my $j_stop ( $journey->route ) {
+ push(
+ @route,
+ [
+ $j_stop->full_name,
+ $j_stop->id_num,
+ {
+ sched_arr => _epoch( $j_stop->sched_arr ),
+ sched_dep => _epoch( $j_stop->sched_dep ),
+ rt_arr => _epoch( $j_stop->rt_arr ),
+ rt_dep => _epoch( $j_stop->rt_dep ),
+ arr_delay => $j_stop->arr_delay,
+ dep_delay => $j_stop->dep_delay,
+ efa_load => $j_stop->occupancy,
+ lat => $j_stop->latlon->[0],
+ lon => $j_stop->latlon->[1],
+ }
+ ]
+ );
+ }
+ $db->insert(
+ 'in_transit',
+ {
+ user_id => $uid,
+ cancelled => 0, # TODO
+ checkin_station_id => $stop->id_num,
+ checkin_time => $now,
+ dep_platform => $stop->platform,
+ train_type => $journey->type // q{},
+ train_line => $journey->line,
+ train_no => $journey->number // q{},
+ train_id => $opt{trip_id},
+ sched_departure => $stop->sched_dep,
+ real_departure => $stop->rt_dep // $stop->sched_dep,
+ route => $json->encode( \@route ),
+ data => JSON->new->encode(
+ {
+ rt => $stop->rt_dep ? 1 : 0,
+ %{ $data // {} }
+ }
+ ),
+ backend_id => $backend_id,
+ }
+ );
+ }
+ elsif ( $journey
+ and $stop
+ and ref($journey) eq 'Travel::Status::DE::HAFAS::Journey' )
+ {
my @route;
my $product = $journey->product_at( $stop->loc->eva )
// $journey->product;
@@ -198,9 +247,10 @@ sub add {
}
);
}
- elsif ( $journey and $stop ) {
-
- # DBRIS
+ elsif ( $journey
+ and $stop
+ and ref($journey) eq 'Travel::Status::DE::DBRIS::Journey' )
+ {
my $number = $journey->train_no // $journey->number // $train_suffix;
my $line;
@@ -284,9 +334,10 @@ sub add {
}
);
}
- elsif ( $journey and $stopover ) {
-
- # MOTIS
+ elsif ( $journey
+ and $stopover
+ and ref($journey) eq 'Travel::Status::MOTIS::Trip' )
+ {
my @route;
for my $journey_stopover ( $journey->stopovers ) {
push(
@@ -340,7 +391,7 @@ sub add {
);
}
else {
- die('neither train nor journey specified');
+ die('invalid arguments / argument types passed to InTransit->add');
}
}
@@ -944,6 +995,41 @@ sub update_departure_dbris {
);
}
+sub update_departure_efa {
+ my ( $self, %opt ) = @_;
+ my $uid = $opt{uid};
+ my $db = $opt{db} // $self->{pg}->db;
+ my $dep_eva = $opt{dep_eva};
+ my $arr_eva = $opt{arr_eva};
+ my $journey = $opt{journey};
+ my $stop = $opt{stop};
+ my $json = JSON->new;
+
+ my $res_h = $db->select( 'in_transit', ['data'], { user_id => $uid } )
+ ->expand->hash;
+ my $ephemeral_data = $res_h ? $res_h->{data} : {};
+ if ( $stop->rt_dep ) {
+ $ephemeral_data->{rt} = 1;
+ }
+
+ # selecting on user_id and train_no avoids a race condition if a user checks
+ # into a new train while we are fetching data for their previous journey. In
+ # this case, the new train would receive data from the previous journey.
+ $db->update(
+ 'in_transit',
+ {
+ data => $json->encode($ephemeral_data),
+ real_departure => $stop->rt_dep,
+ },
+ {
+ user_id => $uid,
+ train_id => $opt{trip_id},
+ checkin_station_id => $dep_eva,
+ checkout_station_id => $arr_eva,
+ }
+ );
+}
+
sub update_departure_motis {
my ( $self, %opt ) = @_;
my $uid = $opt{uid};
@@ -1137,6 +1223,67 @@ sub update_arrival_dbris {
);
}
+sub update_arrival_efa {
+ my ( $self, %opt ) = @_;
+ my $uid = $opt{uid};
+ my $db = $opt{db} // $self->{pg}->db;
+ my $dep_eva = $opt{dep_eva};
+ my $arr_eva = $opt{arr_eva};
+ my $journey = $opt{journey};
+ my $stop = $opt{stop};
+ my $json = JSON->new;
+
+ my $res_h
+ = $db->select( 'in_transit', [ 'data', 'route' ], { user_id => $uid } )
+ ->expand->hash;
+ my $ephemeral_data = $res_h ? $res_h->{data} : {};
+ my $old_route = $res_h ? $res_h->{route} : [];
+
+ if ( $stop->rt_arr ) {
+ $ephemeral_data->{rt} = 1;
+ }
+
+ my @route;
+ for my $j_stop ( $journey->route ) {
+ push(
+ @route,
+ [
+ $j_stop->full_name,
+ $j_stop->id_num,
+ {
+ sched_arr => _epoch( $j_stop->sched_arr ),
+ sched_dep => _epoch( $j_stop->sched_dep ),
+ rt_arr => _epoch( $j_stop->rt_arr ),
+ rt_dep => _epoch( $j_stop->rt_dep ),
+ arr_delay => $j_stop->arr_delay,
+ dep_delay => $j_stop->dep_delay,
+ efa_load => $j_stop->occupancy,
+ lat => $j_stop->latlon->[0],
+ lon => $j_stop->latlon->[1],
+ }
+ ]
+ );
+ }
+
+ # selecting on user_id and train_no avoids a race condition if a user checks
+ # into a new train while we are fetching data for their previous journey. In
+ # this case, the new train would receive data from the previous journey.
+ $db->update(
+ 'in_transit',
+ {
+ data => $json->encode($ephemeral_data),
+ real_arrival => $stop->rt_arr,
+ route => $json->encode( [@route] ),
+ },
+ {
+ user_id => $uid,
+ train_id => $opt{trip_id},
+ checkin_station_id => $dep_eva,
+ checkout_station_id => $arr_eva,
+ }
+ );
+}
+
sub update_arrival_motis {
my ( $self, %opt ) = @_;
my $uid = $opt{uid};
diff --git a/lib/Travelynx/Model/Journeys.pm b/lib/Travelynx/Model/Journeys.pm
index 8efbab2..1662787 100755
--- a/lib/Travelynx/Model/Journeys.pm
+++ b/lib/Travelynx/Model/Journeys.pm
@@ -1735,6 +1735,8 @@ sub compute_stats {
sub get_stats {
my ( $self, %opt ) = @_;
+ $self->{log}->debug("get_stats");
+
if ( $opt{cancelled} ) {
$self->{log}
->warn('get_journey_stats called with illegal option cancelled => 1');
@@ -1761,9 +1763,12 @@ sub get_stats {
)
)
{
+ $self->{log}->debug("got cached journey stats for $year/$month");
return $stats;
}
+ $self->{log}->debug("computing journey stats for $year/$month");
+
my $interval_start = DateTime->new(
time_zone => 'Europe/Berlin',
year => 2000,
diff --git a/lib/Travelynx/Model/Stations.pm b/lib/Travelynx/Model/Stations.pm
index 174b3b4..bf35d1a 100644
--- a/lib/Travelynx/Model/Stations.pm
+++ b/lib/Travelynx/Model/Stations.pm
@@ -23,12 +23,15 @@ sub get_backend_id {
# special case
return 0;
}
- if ( $opt{hafas} and $self->{backend_id}{hafas}{ $opt{hafas} } ) {
- return $self->{backend_id}{hafas}{ $opt{hafas} };
- }
if ( $opt{dbris} and $self->{backend_id}{dbris}{ $opt{dbris} } ) {
return $self->{backend_id}{dbris}{ $opt{dbris} };
}
+ if ( $opt{efa} and $self->{backend_id}{efa}{ $opt{efa} } ) {
+ return $self->{backend_id}{efa}{ $opt{efa} };
+ }
+ if ( $opt{hafas} and $self->{backend_id}{hafas}{ $opt{hafas} } ) {
+ return $self->{backend_id}{hafas}{ $opt{hafas} };
+ }
if ( $opt{motis} and $self->{backend_id}{motis}{ $opt{motis} } ) {
return $self->{backend_id}{motis}{ $opt{motis} };
}
@@ -47,6 +50,17 @@ sub get_backend_id {
)->hash->{id};
$self->{backend_id}{dbris}{ $opt{dbris} } = $backend_id;
}
+ elsif ( $opt{efa} ) {
+ $backend_id = $db->select(
+ 'backends',
+ ['id'],
+ {
+ efa => 1,
+ name => $opt{efa}
+ }
+ )->hash->{id};
+ $self->{backend_id}{efa}{ $opt{efa} } = $backend_id;
+ }
elsif ( $opt{hafas} ) {
$backend_id = $db->select(
'backends',
@@ -100,7 +114,7 @@ sub get_backends {
$opt{db} //= $self->{pg}->db;
my $res = $opt{db}->select( 'backends',
- [ 'id', 'name', 'iris', 'hafas', 'dbris', 'motis' ] );
+ [ 'id', 'name', 'dbris', 'efa', 'hafas', 'iris', 'motis' ] );
my @ret;
while ( my $row = $res->hash ) {
@@ -109,9 +123,10 @@ sub get_backends {
{
id => $row->{id},
name => $row->{name},
- iris => $row->{iris},
dbris => $row->{dbris},
+ efa => $row->{efa},
hafas => $row->{hafas},
+ iris => $row->{iris},
motis => $row->{motis},
}
);
@@ -166,6 +181,44 @@ sub add_or_update {
return;
}
+ if ( $opt{efa} ) {
+ if (
+ my $s = $self->get_by_eva(
+ $stop->id_num,
+ db => $opt{db},
+ backend_id => $opt{backend_id}
+ )
+ )
+ {
+ $opt{db}->update(
+ 'stations',
+ {
+ name => $stop->full_name,
+ lat => $stop->latlon->[0],
+ lon => $stop->latlon->[1],
+ archived => 0
+ },
+ {
+ eva => $stop->id_num,
+ source => $opt{backend_id}
+ }
+ );
+ return;
+ }
+ $opt{db}->insert(
+ 'stations',
+ {
+ eva => $stop->id_num,
+ name => $stop->full_name,
+ lat => $stop->latlon->[0],
+ lon => $stop->latlon->[1],
+ source => $opt{backend_id},
+ archived => 0
+ }
+ );
+ return;
+ }
+
if ( $opt{motis} ) {
if (
my $s = $self->get_by_external_id(
diff --git a/lib/Travelynx/Model/Users.pm b/lib/Travelynx/Model/Users.pm
index 1c3692e..a552633 100644
--- a/lib/Travelynx/Model/Users.pm
+++ b/lib/Travelynx/Model/Users.pm
@@ -418,7 +418,7 @@ sub get {
. 'extract(epoch from registered_at) as registered_at_ts, '
. 'extract(epoch from last_seen) as last_seen_ts, '
. 'extract(epoch from deletion_requested) as deletion_requested_ts, '
- . 'backend_id, backend_name, hafas, dbris, motis',
+ . 'backend_id, backend_name, dbris, efa, hafas, motis',
{ id => $uid }
)->hash;
if ($user) {
@@ -458,6 +458,7 @@ sub get {
backend_id => $user->{backend_id},
backend_name => $user->{backend_name},
backend_dbris => $user->{dbris},
+ backend_efa => $user->{efa},
backend_hafas => $user->{hafas},
backend_motis => $user->{motis},
};