Loading lib/DBInfoscreen/Controller/Stationboard.pm +109 −89 Original line number Diff line number Diff line Loading @@ -419,8 +419,36 @@ sub render_train { $departure->{wr_link} = undef; } my ( $route_ts, $route_info, $trainsearch ) = $self->hafas->get_route_timestamps( train => $result ); my $linetype = 'bahn'; if ( $departure->{train_type} eq 'S' ) { $linetype = 'sbahn'; } elsif ($departure->{train_type} eq 'IC' or $departure->{train_type} eq 'ICE' or $departure->{train_type} eq 'EC' or $departure->{train_type} eq 'ECE' or $departure->{train_type} eq 'EN' ) { $linetype = 'fern'; } elsif ($departure->{train_type} eq 'THA' or $departure->{train_type} eq 'TGV' or $departure->{train_type} eq 'FLX' or $departure->{train_type} eq 'NJ' ) { $linetype = 'ext'; } elsif ( $departure->{train_line} and $departure->{train_line} =~ m{^S\d} ) { $linetype = 'sbahn'; } $self->render_later; $self->hafas->get_route_timestamps_p( train => $result )->then( sub { my ( $route_ts, $route_info, $trainsearch ) = @_; $departure->{trip_id} = $trainsearch->{trip_id}; Loading @@ -439,7 +467,10 @@ sub render_train { @iris_stations ) { unshift( @{ $departure->{route_pre_diff} }, @missing_pre ); unshift( @{ $departure->{route_pre_diff} }, @missing_pre ); last; } push( Loading @@ -459,7 +490,10 @@ sub render_train { @iris_stations ) { push( @{ $departure->{route_post_diff} }, @missing_post ); push( @{ $departure->{route_post_diff} }, @missing_post ); last; } unshift( Loading @@ -478,7 +512,8 @@ sub render_train { @{ $departure->{route_post_diff} } ) { for my $key ( keys %{ $route_ts->{ $elem->{name} } // {} } ) { for my $key ( keys %{ $route_ts->{ $elem->{name} } // {} } ) { $elem->{$key} = $route_ts->{ $elem->{name} }{$key}; } } Loading @@ -489,42 +524,25 @@ sub render_train { $departure->{messages}{him} = $him; for my $message ( @{$him} ) { if ( $message->{display} ) { push( @him_messages, [ $message->{header}, $message->{lead} ] ); push( @him_messages, [ $message->{header}, $message->{lead} ] ); } } for my $message ( @{ $departure->{moreinfo} // [] } ) { my $m = $message->[1]; @him_messages = grep { $_->[0] !~ m{Information\. $m\.$} } @him_messages; = grep { $_->[0] !~ m{Information\. $m\.$} } @him_messages; } unshift( @{ $departure->{moreinfo} }, @him_messages ); } my $linetype = 'bahn'; if ( $departure->{train_type} eq 'S' ) { $linetype = 'sbahn'; } elsif ($departure->{train_type} eq 'IC' or $departure->{train_type} eq 'ICE' or $departure->{train_type} eq 'EC' or $departure->{train_type} eq 'ECE' or $departure->{train_type} eq 'EN' ) { $linetype = 'fern'; } elsif ($departure->{train_type} eq 'THA' or $departure->{train_type} eq 'TGV' or $departure->{train_type} eq 'FLX' or $departure->{train_type} eq 'NJ' ) { $linetype = 'ext'; } elsif ( $departure->{train_line} and $departure->{train_line} =~ m{^S\d} ) { $linetype = 'sbahn'; )->catch( sub { # nop } )->finally( sub { $self->render( '_train_details', departure => $departure, Loading @@ -534,6 +552,8 @@ sub render_train { station_name => $station_name, ); } )->wait; } sub handle_result { my ( $self, $data ) = @_; Loading lib/DBInfoscreen/Helper/HAFAS.pm +128 −194 Original line number Diff line number Diff line Loading @@ -24,46 +24,13 @@ sub new { } sub hafas_json_req { my ( $self, $cache, $url ) = @_; if ( my $content = $cache->thaw($url) ) { return $content; } my $res = eval { $self->{user_agent}->get( $url => $self->{header} )->result }; if ($@) { $self->{log}->debug("hafas_json_req($url): $@"); return; } if ( $res->is_error ) { return; } my $body = encode( 'utf-8', decode( 'ISO-8859-15', $res->body ) ); $body =~ s{^TSLs[.]sls = }{}; $body =~ s{;$}{}; $body =~ s{(}{(}g; $body =~ s{)}{)}g; my $json = decode_json($body); $cache->freeze( $url, $json ); return $json; } sub get_json_p { my ( $self, $cache, $url ) = @_; my $promise = Mojo::Promise->new; if ( my $content = $cache->thaw($url) ) { $promise->resolve($content); return $promise; return $promise->resolve($content); } $self->{user_agent}->request_timeout(5)->get_p( $url => $self->{header} ) Loading Loading @@ -106,26 +73,31 @@ sub get_json_p { return $promise; } sub hafas_xml_req { sub get_xml_p { my ( $self, $cache, $url ) = @_; my $promise = Mojo::Promise->new; if ( my $content = $cache->thaw($url) ) { return $content; return $promise->resolve($content); } my $res = eval { $self->{user_agent}->get( $url => $self->{header} )->result }; $self->{user_agent}->request_timeout(5)->get_p( $url => $self->{header} ) ->then( sub { my ($tx) = @_; if ($@) { $self->{log}->debug("hafas_xml_req($url): $@"); return; } if ( $res->is_error ) { if ( my $err = $tx->error ) { $cache->freeze( $url, {} ); $self->{log}->warn( "hafas->get_xml_p($url): HTTP $err->{code} $err->{message}" ); $promise->reject( "GET $url returned HTTP $err->{code} $err->{message}"); return; } my $body = decode( 'ISO-8859-15', $res->body ); my $body = decode( 'ISO-8859-15', $tx->res->body ); # <SDay text="... > ..."> is invalid HTML, but present # regardless. As it is the last tag, we just throw it away. Loading @@ -137,6 +109,7 @@ sub hafas_xml_req { if ($@) { $cache->freeze( $url, {} ); $promise->reject; return; } Loading Loading @@ -172,70 +145,14 @@ sub hafas_xml_req { } $cache->freeze( $url, $ret ); $promise->resolve($ret); return $ret; } sub trainsearch { my ( $self, %opt ) = @_; my $base = 'https://reiseauskunft.bahn.de/bin/trainsearch.exe/dn?L=vs_json&start=yes&rt=1'; if ( not $opt{date_yy} ) { my $now = DateTime->now( time_zone => 'Europe/Berlin' ); $opt{date_yy} = $now->strftime('%d.%m.%y'); $opt{date_yyyy} = $now->strftime('%d.%m.%Y'); } my $trainsearch = $self->hafas_json_req( $self->{realtime_cache}, "${base}&date=$opt{date_yy}&trainname=$opt{train_no}" ); if ( not $trainsearch ) { return; } # Fallback: Take first result my $result = $trainsearch->{suggestions}[0]; # Try finding a result for the current date for my $suggestion ( @{ $trainsearch->{suggestions} // [] } ) { # Drunken API, sail with care. Both date formats are used interchangeably if ( exists $suggestion->{depDate} and ( $suggestion->{depDate} eq $opt{date_yy} or $suggestion->{depDate} eq $opt{date_yyyy} ) ) { # Train numbers are not unique, e.g. IC 149 refers both to the # InterCity service Amsterdam -> Berlin and to the InterCity service # Koebenhavns Lufthavn st -> Aarhus. One workaround is making # requests with the stationFilter=80 parameter. Checking the origin # station seems to be the more generic solution, so we do that # instead. if ( $opt{train_origin} and $suggestion->{dep} eq $opt{train_origin} ) { $result = $suggestion; last; } } } if ($result) { # The trip_id's date part doesn't seem to matter -- so far, HAFAS is # happy as long as the date part starts with a number. HAFAS-internal # tripIDs use this format (withouth leading zero for day of month < 10) # though, so let's stick with it. my $date_map = $opt{date_yyyy}; $date_map =~ tr{.}{}d; $result->{trip_id} = sprintf( '1|%d|%d|%d|%s', $result->{id}, $result->{cycle}, $result->{pool}, $date_map ); )->catch( sub { } return $result; )->wait; } sub trainsearch_p { Loading Loading @@ -320,9 +237,11 @@ sub trainsearch_p { return $promise; } sub get_route_timestamps { sub get_route_timestamps_p { my ( $self, %opt ) = @_; my $promise = Mojo::Promise->new; if ( $opt{train} ) { $opt{date_yy} = $opt{train}->start->strftime('%d.%m.%y'); $opt{date_yyyy} = $opt{train}->start->strftime('%d.%m.%Y'); Loading @@ -335,26 +254,29 @@ sub get_route_timestamps { $opt{date_yyyy} = $now->strftime('%d.%m.%Y'); } my $trainsearch_result = $self->trainsearch(%opt); if ( not $trainsearch_result ) { return; } my $trainlink = $trainsearch_result->{trainLink}; my $base = 'https://reiseauskunft.bahn.de/bin/traininfo.exe/dn'; my ( $trainsearch_result, $trainlink, $traininfo ); my $traininfo = $self->hafas_json_req( $self->{realtime_cache}, $self->trainsearch_p(%opt)->then( sub { ($trainsearch_result) = @_; $trainlink = $trainsearch_result->{trainLink}; return $self->get_json_p( $self->{realtime_cache}, "${base}/${trainlink}?rt=1&date=$opt{date_yy}&L=vs_json" ); } )->then( sub { ($traininfo) = @_; if ( not $traininfo or $traininfo->{error} ) { $promise->reject; return; } my $traindelay = $self->hafas_xml_req( $self->{realtime_cache}, return $self->get_xml_p( $self->{realtime_cache}, "${base}/${trainlink}?rt=1&date=$opt{date_yy}&L=vs_java3" ); } )->then( sub { my ($traindelay) = @_; my $ret = {}; my $strp = DateTime::Format::Strptime->new( Loading @@ -362,7 +284,9 @@ sub get_route_timestamps { time_zone => 'Europe/Berlin', ); for my $station ( @{ $traininfo->{suggestions}[0]{locations} // [] } ) { for my $station ( @{ $traininfo->{suggestions}[0]{locations} // [] } ) { my $name = $station->{name}; my $arr = $station->{arrDate} . ' ' . $station->{arrTime}; my $dep = $station->{depDate} . ' ' . $station->{depTime}; Loading @@ -389,7 +313,17 @@ sub get_route_timestamps { } } return ( $ret, $traindelay // {}, $trainsearch_result ); $promise->resolve( $ret, $traindelay // {}, $trainsearch_result ); return; } )->catch( sub { $promise->reject; return; } )->wait; return $promise; } # Input: (HAFAS TripID, line number) Loading Loading
lib/DBInfoscreen/Controller/Stationboard.pm +109 −89 Original line number Diff line number Diff line Loading @@ -419,8 +419,36 @@ sub render_train { $departure->{wr_link} = undef; } my ( $route_ts, $route_info, $trainsearch ) = $self->hafas->get_route_timestamps( train => $result ); my $linetype = 'bahn'; if ( $departure->{train_type} eq 'S' ) { $linetype = 'sbahn'; } elsif ($departure->{train_type} eq 'IC' or $departure->{train_type} eq 'ICE' or $departure->{train_type} eq 'EC' or $departure->{train_type} eq 'ECE' or $departure->{train_type} eq 'EN' ) { $linetype = 'fern'; } elsif ($departure->{train_type} eq 'THA' or $departure->{train_type} eq 'TGV' or $departure->{train_type} eq 'FLX' or $departure->{train_type} eq 'NJ' ) { $linetype = 'ext'; } elsif ( $departure->{train_line} and $departure->{train_line} =~ m{^S\d} ) { $linetype = 'sbahn'; } $self->render_later; $self->hafas->get_route_timestamps_p( train => $result )->then( sub { my ( $route_ts, $route_info, $trainsearch ) = @_; $departure->{trip_id} = $trainsearch->{trip_id}; Loading @@ -439,7 +467,10 @@ sub render_train { @iris_stations ) { unshift( @{ $departure->{route_pre_diff} }, @missing_pre ); unshift( @{ $departure->{route_pre_diff} }, @missing_pre ); last; } push( Loading @@ -459,7 +490,10 @@ sub render_train { @iris_stations ) { push( @{ $departure->{route_post_diff} }, @missing_post ); push( @{ $departure->{route_post_diff} }, @missing_post ); last; } unshift( Loading @@ -478,7 +512,8 @@ sub render_train { @{ $departure->{route_post_diff} } ) { for my $key ( keys %{ $route_ts->{ $elem->{name} } // {} } ) { for my $key ( keys %{ $route_ts->{ $elem->{name} } // {} } ) { $elem->{$key} = $route_ts->{ $elem->{name} }{$key}; } } Loading @@ -489,42 +524,25 @@ sub render_train { $departure->{messages}{him} = $him; for my $message ( @{$him} ) { if ( $message->{display} ) { push( @him_messages, [ $message->{header}, $message->{lead} ] ); push( @him_messages, [ $message->{header}, $message->{lead} ] ); } } for my $message ( @{ $departure->{moreinfo} // [] } ) { my $m = $message->[1]; @him_messages = grep { $_->[0] !~ m{Information\. $m\.$} } @him_messages; = grep { $_->[0] !~ m{Information\. $m\.$} } @him_messages; } unshift( @{ $departure->{moreinfo} }, @him_messages ); } my $linetype = 'bahn'; if ( $departure->{train_type} eq 'S' ) { $linetype = 'sbahn'; } elsif ($departure->{train_type} eq 'IC' or $departure->{train_type} eq 'ICE' or $departure->{train_type} eq 'EC' or $departure->{train_type} eq 'ECE' or $departure->{train_type} eq 'EN' ) { $linetype = 'fern'; } elsif ($departure->{train_type} eq 'THA' or $departure->{train_type} eq 'TGV' or $departure->{train_type} eq 'FLX' or $departure->{train_type} eq 'NJ' ) { $linetype = 'ext'; } elsif ( $departure->{train_line} and $departure->{train_line} =~ m{^S\d} ) { $linetype = 'sbahn'; )->catch( sub { # nop } )->finally( sub { $self->render( '_train_details', departure => $departure, Loading @@ -534,6 +552,8 @@ sub render_train { station_name => $station_name, ); } )->wait; } sub handle_result { my ( $self, $data ) = @_; Loading
lib/DBInfoscreen/Helper/HAFAS.pm +128 −194 Original line number Diff line number Diff line Loading @@ -24,46 +24,13 @@ sub new { } sub hafas_json_req { my ( $self, $cache, $url ) = @_; if ( my $content = $cache->thaw($url) ) { return $content; } my $res = eval { $self->{user_agent}->get( $url => $self->{header} )->result }; if ($@) { $self->{log}->debug("hafas_json_req($url): $@"); return; } if ( $res->is_error ) { return; } my $body = encode( 'utf-8', decode( 'ISO-8859-15', $res->body ) ); $body =~ s{^TSLs[.]sls = }{}; $body =~ s{;$}{}; $body =~ s{(}{(}g; $body =~ s{)}{)}g; my $json = decode_json($body); $cache->freeze( $url, $json ); return $json; } sub get_json_p { my ( $self, $cache, $url ) = @_; my $promise = Mojo::Promise->new; if ( my $content = $cache->thaw($url) ) { $promise->resolve($content); return $promise; return $promise->resolve($content); } $self->{user_agent}->request_timeout(5)->get_p( $url => $self->{header} ) Loading Loading @@ -106,26 +73,31 @@ sub get_json_p { return $promise; } sub hafas_xml_req { sub get_xml_p { my ( $self, $cache, $url ) = @_; my $promise = Mojo::Promise->new; if ( my $content = $cache->thaw($url) ) { return $content; return $promise->resolve($content); } my $res = eval { $self->{user_agent}->get( $url => $self->{header} )->result }; $self->{user_agent}->request_timeout(5)->get_p( $url => $self->{header} ) ->then( sub { my ($tx) = @_; if ($@) { $self->{log}->debug("hafas_xml_req($url): $@"); return; } if ( $res->is_error ) { if ( my $err = $tx->error ) { $cache->freeze( $url, {} ); $self->{log}->warn( "hafas->get_xml_p($url): HTTP $err->{code} $err->{message}" ); $promise->reject( "GET $url returned HTTP $err->{code} $err->{message}"); return; } my $body = decode( 'ISO-8859-15', $res->body ); my $body = decode( 'ISO-8859-15', $tx->res->body ); # <SDay text="... > ..."> is invalid HTML, but present # regardless. As it is the last tag, we just throw it away. Loading @@ -137,6 +109,7 @@ sub hafas_xml_req { if ($@) { $cache->freeze( $url, {} ); $promise->reject; return; } Loading Loading @@ -172,70 +145,14 @@ sub hafas_xml_req { } $cache->freeze( $url, $ret ); $promise->resolve($ret); return $ret; } sub trainsearch { my ( $self, %opt ) = @_; my $base = 'https://reiseauskunft.bahn.de/bin/trainsearch.exe/dn?L=vs_json&start=yes&rt=1'; if ( not $opt{date_yy} ) { my $now = DateTime->now( time_zone => 'Europe/Berlin' ); $opt{date_yy} = $now->strftime('%d.%m.%y'); $opt{date_yyyy} = $now->strftime('%d.%m.%Y'); } my $trainsearch = $self->hafas_json_req( $self->{realtime_cache}, "${base}&date=$opt{date_yy}&trainname=$opt{train_no}" ); if ( not $trainsearch ) { return; } # Fallback: Take first result my $result = $trainsearch->{suggestions}[0]; # Try finding a result for the current date for my $suggestion ( @{ $trainsearch->{suggestions} // [] } ) { # Drunken API, sail with care. Both date formats are used interchangeably if ( exists $suggestion->{depDate} and ( $suggestion->{depDate} eq $opt{date_yy} or $suggestion->{depDate} eq $opt{date_yyyy} ) ) { # Train numbers are not unique, e.g. IC 149 refers both to the # InterCity service Amsterdam -> Berlin and to the InterCity service # Koebenhavns Lufthavn st -> Aarhus. One workaround is making # requests with the stationFilter=80 parameter. Checking the origin # station seems to be the more generic solution, so we do that # instead. if ( $opt{train_origin} and $suggestion->{dep} eq $opt{train_origin} ) { $result = $suggestion; last; } } } if ($result) { # The trip_id's date part doesn't seem to matter -- so far, HAFAS is # happy as long as the date part starts with a number. HAFAS-internal # tripIDs use this format (withouth leading zero for day of month < 10) # though, so let's stick with it. my $date_map = $opt{date_yyyy}; $date_map =~ tr{.}{}d; $result->{trip_id} = sprintf( '1|%d|%d|%d|%s', $result->{id}, $result->{cycle}, $result->{pool}, $date_map ); )->catch( sub { } return $result; )->wait; } sub trainsearch_p { Loading Loading @@ -320,9 +237,11 @@ sub trainsearch_p { return $promise; } sub get_route_timestamps { sub get_route_timestamps_p { my ( $self, %opt ) = @_; my $promise = Mojo::Promise->new; if ( $opt{train} ) { $opt{date_yy} = $opt{train}->start->strftime('%d.%m.%y'); $opt{date_yyyy} = $opt{train}->start->strftime('%d.%m.%Y'); Loading @@ -335,26 +254,29 @@ sub get_route_timestamps { $opt{date_yyyy} = $now->strftime('%d.%m.%Y'); } my $trainsearch_result = $self->trainsearch(%opt); if ( not $trainsearch_result ) { return; } my $trainlink = $trainsearch_result->{trainLink}; my $base = 'https://reiseauskunft.bahn.de/bin/traininfo.exe/dn'; my ( $trainsearch_result, $trainlink, $traininfo ); my $traininfo = $self->hafas_json_req( $self->{realtime_cache}, $self->trainsearch_p(%opt)->then( sub { ($trainsearch_result) = @_; $trainlink = $trainsearch_result->{trainLink}; return $self->get_json_p( $self->{realtime_cache}, "${base}/${trainlink}?rt=1&date=$opt{date_yy}&L=vs_json" ); } )->then( sub { ($traininfo) = @_; if ( not $traininfo or $traininfo->{error} ) { $promise->reject; return; } my $traindelay = $self->hafas_xml_req( $self->{realtime_cache}, return $self->get_xml_p( $self->{realtime_cache}, "${base}/${trainlink}?rt=1&date=$opt{date_yy}&L=vs_java3" ); } )->then( sub { my ($traindelay) = @_; my $ret = {}; my $strp = DateTime::Format::Strptime->new( Loading @@ -362,7 +284,9 @@ sub get_route_timestamps { time_zone => 'Europe/Berlin', ); for my $station ( @{ $traininfo->{suggestions}[0]{locations} // [] } ) { for my $station ( @{ $traininfo->{suggestions}[0]{locations} // [] } ) { my $name = $station->{name}; my $arr = $station->{arrDate} . ' ' . $station->{arrTime}; my $dep = $station->{depDate} . ' ' . $station->{depTime}; Loading @@ -389,7 +313,17 @@ sub get_route_timestamps { } } return ( $ret, $traindelay // {}, $trainsearch_result ); $promise->resolve( $ret, $traindelay // {}, $trainsearch_result ); return; } )->catch( sub { $promise->reject; return; } )->wait; return $promise; } # Input: (HAFAS TripID, line number) Loading