Loading lib/Travelynx/Controller/Traveling.pm +111 −22 Original line number Diff line number Diff line Loading @@ -77,19 +77,21 @@ sub get_connecting_trains_p { } my $can_check_in = not $arr_epoch || ( $arr_countdown // 1 ) < 0; my $lookahead = $can_check_in ? 40 : ( ( ${arr_countdown} // 0 ) / 60 + 40 ); my $iris_promise = Mojo::Promise->new; $self->iris->get_departures_p( station => $eva, lookbehind => 10, lookahead => $can_check_in ? 40 : ( ( ${arr_countdown} // 0 ) / 60 + 40 ), lookahead => $lookahead, with_related => 1 )->then( sub { my ($stationboard) = @_; if ( $stationboard->{errstr} ) { $promise->reject( $stationboard->{errstr} ); $iris_promise->reject( $stationboard->{errstr} ); return; } Loading Loading @@ -213,22 +215,107 @@ sub get_connecting_trains_p { = 'Anschluss könnte knapp werden'; $train->{interchange_icon} = 'directions_run'; } } } $iris_promise->resolve( [ @results, @cancellations ] ); return; } )->catch( sub { $iris_promise->reject(@_); return; } )->wait; my $hafas_promise = Mojo::Promise->new; my $rest_api = $self->config->{backend}{hafas_rest_api}; $self->hafas->get_json_p( "${rest_api}/stops/${eva}/departures?results=120&duration=${lookahead}&stopovers=true&when=10 minutes ago", realtime => 1, encoding => 'utf-8' )->then( sub { my ($json) = @_; $hafas_promise->resolve($json); return; } )->catch( sub { # HAFAS data is optional. # Errors are logged by get_json_p and can be silently ignored here. $hafas_promise->resolve( [] ); return; } )->wait; Mojo::Promise->all( $iris_promise, $hafas_promise )->then( sub { my ( $iris, $hafas ) = @_; my @iris_trains = @{ $iris->[0] }; my @hafas_trains = @{ $hafas->[0] }; my $strp = DateTime::Format::Strptime->new( pattern => '%Y-%m-%dT%H:%M:%S%z', time_zone => 'Europe/Berlin', ); #else { # $train->{interchange_text} = 'Anschluss wird voraussichtlich erreicht'; # $train->{interchange_icon} = 'check'; #} # We've already got a list of connecting trains; this function # only adds further information to them. We ignore errors, as # partial data is better than no data. eval { for my $iris_train (@iris_trains) { if ( $iris_train->[0]->departure_is_cancelled ) { continue; } for my $hafas_train (@hafas_trains) { if ( $hafas_train->{line}{fahrtNr} == $iris_train->[0]->train_no ) { for my $stop ( @{ $hafas_train->{nextStopovers} // [] } ) { if ( $stop->{stop}{name} and $stop->{stop}{name} eq $iris_train->[1] and $stop->{arrival} ) { $iris_train->[2] = $strp->parse_datetime( $stop->{arrival} ); if ( $iris_train->[2] and $iris_train->[0]->arrival_delay and $stop->{arrival} eq $stop->{plannedArrival} ) { # If the departure is delayed, but the arrival supposedly on time, we assume that this is an API issue and manually compute the expected arrival time. # This avoids cases where a connection is shown as arriving at its destination before having departed at a previous stop. $iris_train->[2]->add( minutes => $iris_train->[0]->arrival_delay ); } } } } } } }; if ($@) { $self->app->log->error( "get_connecting_trains_p($uid): IRIS/HAFAS merge failed: $@" ); } $promise->resolve( @results, @cancellations ); $promise->resolve( \@iris_trains ); return; } )->catch( sub { $promise->reject(@_); my ($err) = @_; # TODO logging. HAFAS errors should never happen, IRIS errors are noteworthy too. $promise->reject($err); return; } )->wait; return $promise; } Loading @@ -245,13 +332,14 @@ sub homepage { $self->render_later; $self->get_connecting_trains_p->then( sub { my @connecting_trains = @_; my ( $connecting_trains, $transit_fyi ) = @_; $self->render( 'landingpage', version => $self->app->config->{version} // 'UNKNOWN', user_status => $status, connections => \@connecting_trains, connections => $connecting_trains, transit_fyi => $transit_fyi, with_autocomplete => 1, with_geolocation => 1 ); Loading Loading @@ -617,11 +705,12 @@ sub status_card { $self->render_later; $self->get_connecting_trains_p->then( sub { my @connecting_trains = @_; my ( $connecting_trains, $transit_fyi ) = @_; $self->render( '_checked_in', journey => $status, connections => \@connecting_trains connections => $connecting_trains, transit_fyi => $transit_fyi ); } )->catch( Loading @@ -640,11 +729,11 @@ sub status_card { destination_name => $status->{cancellation}{arr_name} )->then( sub { my (@connecting_trains) = @_; my ($connecting_trains) = @_; $self->render( '_cancelled_departure', journey => $status->{cancellation}, connections => \@connecting_trains connections => $connecting_trains ); } )->catch( Loading @@ -662,11 +751,11 @@ sub status_card { $self->render_later; $self->get_connecting_trains_p->then( sub { my @connecting_trains = @_; my ($connecting_trains) = @_; $self->render( '_checked_out', journey => $status, connections => \@connecting_trains connections => $connecting_trains ); } )->catch( Loading Loading @@ -968,14 +1057,14 @@ sub station { if ($connections_p) { $connections_p->then( sub { my @connecting_trains = @_; my ($connecting_trains) = @_; $self->render( 'departures', eva => $status->{station_eva}, results => \@results, station => $status->{station_name}, related_stations => $status->{related_stations}, connections => \@connecting_trains, connections => $connecting_trains, title => "travelynx: $status->{station_name}", version => $self->app->config->{version} // 'UNKNOWN', Loading templates/_connections.html.ep +4 −3 Original line number Diff line number Diff line <div><table class="striped"><tbody> % for my $res (@{$connections}) { % my ($train, $via) = @{$res}; % my ($train, $via, $via_arr) = @{$res}; % $via_arr = $via_arr ? $via_arr->strftime('%H:%M') : q{}; % my $td_class = ''; % my $link_class = 'action-checkin'; % if ($train->is_cancelled) { Loading @@ -23,10 +24,10 @@ </td> <td class="<%= $td_class %>"> % if ($checkin_from) { <a><%= $via %></a> <a><%= $via %><br/><%= $via_arr %></a> % } % else { %= $via <%= $via %><br/><%= $via_arr %> % } % if ($train->{message_id}{96} or $train->{message_id}{97}) { <i class="material-icons tiny" aria-label="Zug ist überbesetzt">warning</i> Loading Loading
lib/Travelynx/Controller/Traveling.pm +111 −22 Original line number Diff line number Diff line Loading @@ -77,19 +77,21 @@ sub get_connecting_trains_p { } my $can_check_in = not $arr_epoch || ( $arr_countdown // 1 ) < 0; my $lookahead = $can_check_in ? 40 : ( ( ${arr_countdown} // 0 ) / 60 + 40 ); my $iris_promise = Mojo::Promise->new; $self->iris->get_departures_p( station => $eva, lookbehind => 10, lookahead => $can_check_in ? 40 : ( ( ${arr_countdown} // 0 ) / 60 + 40 ), lookahead => $lookahead, with_related => 1 )->then( sub { my ($stationboard) = @_; if ( $stationboard->{errstr} ) { $promise->reject( $stationboard->{errstr} ); $iris_promise->reject( $stationboard->{errstr} ); return; } Loading Loading @@ -213,22 +215,107 @@ sub get_connecting_trains_p { = 'Anschluss könnte knapp werden'; $train->{interchange_icon} = 'directions_run'; } } } $iris_promise->resolve( [ @results, @cancellations ] ); return; } )->catch( sub { $iris_promise->reject(@_); return; } )->wait; my $hafas_promise = Mojo::Promise->new; my $rest_api = $self->config->{backend}{hafas_rest_api}; $self->hafas->get_json_p( "${rest_api}/stops/${eva}/departures?results=120&duration=${lookahead}&stopovers=true&when=10 minutes ago", realtime => 1, encoding => 'utf-8' )->then( sub { my ($json) = @_; $hafas_promise->resolve($json); return; } )->catch( sub { # HAFAS data is optional. # Errors are logged by get_json_p and can be silently ignored here. $hafas_promise->resolve( [] ); return; } )->wait; Mojo::Promise->all( $iris_promise, $hafas_promise )->then( sub { my ( $iris, $hafas ) = @_; my @iris_trains = @{ $iris->[0] }; my @hafas_trains = @{ $hafas->[0] }; my $strp = DateTime::Format::Strptime->new( pattern => '%Y-%m-%dT%H:%M:%S%z', time_zone => 'Europe/Berlin', ); #else { # $train->{interchange_text} = 'Anschluss wird voraussichtlich erreicht'; # $train->{interchange_icon} = 'check'; #} # We've already got a list of connecting trains; this function # only adds further information to them. We ignore errors, as # partial data is better than no data. eval { for my $iris_train (@iris_trains) { if ( $iris_train->[0]->departure_is_cancelled ) { continue; } for my $hafas_train (@hafas_trains) { if ( $hafas_train->{line}{fahrtNr} == $iris_train->[0]->train_no ) { for my $stop ( @{ $hafas_train->{nextStopovers} // [] } ) { if ( $stop->{stop}{name} and $stop->{stop}{name} eq $iris_train->[1] and $stop->{arrival} ) { $iris_train->[2] = $strp->parse_datetime( $stop->{arrival} ); if ( $iris_train->[2] and $iris_train->[0]->arrival_delay and $stop->{arrival} eq $stop->{plannedArrival} ) { # If the departure is delayed, but the arrival supposedly on time, we assume that this is an API issue and manually compute the expected arrival time. # This avoids cases where a connection is shown as arriving at its destination before having departed at a previous stop. $iris_train->[2]->add( minutes => $iris_train->[0]->arrival_delay ); } } } } } } }; if ($@) { $self->app->log->error( "get_connecting_trains_p($uid): IRIS/HAFAS merge failed: $@" ); } $promise->resolve( @results, @cancellations ); $promise->resolve( \@iris_trains ); return; } )->catch( sub { $promise->reject(@_); my ($err) = @_; # TODO logging. HAFAS errors should never happen, IRIS errors are noteworthy too. $promise->reject($err); return; } )->wait; return $promise; } Loading @@ -245,13 +332,14 @@ sub homepage { $self->render_later; $self->get_connecting_trains_p->then( sub { my @connecting_trains = @_; my ( $connecting_trains, $transit_fyi ) = @_; $self->render( 'landingpage', version => $self->app->config->{version} // 'UNKNOWN', user_status => $status, connections => \@connecting_trains, connections => $connecting_trains, transit_fyi => $transit_fyi, with_autocomplete => 1, with_geolocation => 1 ); Loading Loading @@ -617,11 +705,12 @@ sub status_card { $self->render_later; $self->get_connecting_trains_p->then( sub { my @connecting_trains = @_; my ( $connecting_trains, $transit_fyi ) = @_; $self->render( '_checked_in', journey => $status, connections => \@connecting_trains connections => $connecting_trains, transit_fyi => $transit_fyi ); } )->catch( Loading @@ -640,11 +729,11 @@ sub status_card { destination_name => $status->{cancellation}{arr_name} )->then( sub { my (@connecting_trains) = @_; my ($connecting_trains) = @_; $self->render( '_cancelled_departure', journey => $status->{cancellation}, connections => \@connecting_trains connections => $connecting_trains ); } )->catch( Loading @@ -662,11 +751,11 @@ sub status_card { $self->render_later; $self->get_connecting_trains_p->then( sub { my @connecting_trains = @_; my ($connecting_trains) = @_; $self->render( '_checked_out', journey => $status, connections => \@connecting_trains connections => $connecting_trains ); } )->catch( Loading Loading @@ -968,14 +1057,14 @@ sub station { if ($connections_p) { $connections_p->then( sub { my @connecting_trains = @_; my ($connecting_trains) = @_; $self->render( 'departures', eva => $status->{station_eva}, results => \@results, station => $status->{station_name}, related_stations => $status->{related_stations}, connections => \@connecting_trains, connections => $connecting_trains, title => "travelynx: $status->{station_name}", version => $self->app->config->{version} // 'UNKNOWN', Loading
templates/_connections.html.ep +4 −3 Original line number Diff line number Diff line <div><table class="striped"><tbody> % for my $res (@{$connections}) { % my ($train, $via) = @{$res}; % my ($train, $via, $via_arr) = @{$res}; % $via_arr = $via_arr ? $via_arr->strftime('%H:%M') : q{}; % my $td_class = ''; % my $link_class = 'action-checkin'; % if ($train->is_cancelled) { Loading @@ -23,10 +24,10 @@ </td> <td class="<%= $td_class %>"> % if ($checkin_from) { <a><%= $via %></a> <a><%= $via %><br/><%= $via_arr %></a> % } % else { %= $via <%= $via %><br/><%= $via_arr %> % } % if ($train->{message_id}{96} or $train->{message_id}{97}) { <i class="material-icons tiny" aria-label="Zug ist überbesetzt">warning</i> Loading