package DBInfoscreen; use Mojo::Base 'Mojolicious'; # Copyright (C) 2011-2019 Daniel Friesel <derf+dbf@finalrewind.org> # License: 2-Clause BSD use Cache::File; use Travel::Status::DE::HAFAS; use Travel::Status::DE::HAFAS::StopFinder; use Travel::Status::DE::IRIS::Stations; use utf8; no if $] >= 5.018, warnings => 'experimental::smartmatch'; our $VERSION = qx{git describe --dirty} || '0.05'; my %default = ( backend => 'iris', mode => 'app', admode => 'deparr', ); sub startup { my ($self) = @_; $self->attr( cache_hafas => sub { my ($self) = @_; return Cache::File->new( cache_root => $ENV{DBFAKEDISPLAY_HAFAS_CACHE} // '/tmp/dbf-hafas', default_expires => '180 seconds', lock_level => Cache::File::LOCK_LOCAL(), ); } ); $self->attr( cache_iris_main => sub { my ($self) = @_; return Cache::File->new( cache_root => $ENV{DBFAKEDISPLAY_IRIS_CACHE} // '/tmp/dbf-iris-main', default_expires => '6 hours', lock_level => Cache::File::LOCK_LOCAL(), ); } ); $self->attr( cache_iris_rt => sub { my ($self) = @_; return Cache::File->new( cache_root => $ENV{DBFAKEDISPLAY_IRISRT_CACHE} // '/tmp/dbf-iris-realtime', default_expires => '70 seconds', lock_level => Cache::File::LOCK_LOCAL(), ); } ); $self->helper( 'handle_no_results' => sub { my ( $self, $backend, $station, $errstr ) = @_; if ( $backend eq 'ris' ) { my $db_service = Travel::Status::DE::HAFAS::get_service('DB'); my $sf = Travel::Status::DE::HAFAS::StopFinder->new( url => $db_service->{stopfinder}, input => $station, ); my @candidates = map { [ $_->{name}, $_->{id} ] } $sf->results; if ( @candidates > 1 or ( @candidates == 1 and $candidates[0][1] ne $station ) ) { $self->render( 'landingpage', stationlist => \@candidates, hide_opts => 0 ); return; } } if ( $backend eq 'iris' ) { my @candidates = map { [ $_->[1], $_->[0] ] } Travel::Status::DE::IRIS::Stations::get_station($station); if ( @candidates > 1 or ( @candidates == 1 and $candidates[0][1] ne $station ) ) { $self->render( 'landingpage', stationlist => \@candidates, hide_opts => 0 ); return; } } $self->render( 'landingpage', error => ( $errstr // "Got no results for '$station'" ), hide_opts => 0 ); return; } ); $self->helper( 'handle_no_results_json' => sub { my ( $self, $backend, $station, $errstr, $api_version, $callback ) = @_; $self->res->headers->access_control_allow_origin(q{*}); my $json; if ($errstr) { $json = $self->render_to_string( json => { api_version => $api_version, version => $VERSION, error => $errstr, } ); } else { my @candidates = map { { code => $_->[0], name => $_->[1] } } Travel::Status::DE::IRIS::Stations::get_station($station); if ( @candidates > 1 or ( @candidates == 1 and $candidates[0]{code} ne $station ) ) { $json = $self->render_to_string( json => { api_version => $api_version, version => $VERSION, error => 'ambiguous station code/name', candidates => \@candidates, } ); } else { $json = $self->render_to_string( json => { api_version => $api_version, version => $VERSION, error => ( $errstr // "Got no results for '$station'" ) } ); } } if ($callback) { $self->render( data => "$callback($json);", format => 'json' ); } else { $self->render( data => $json, format => 'json' ); } return; } ); $self->helper( 'is_important' => sub { my ( $self, $stop ) = @_; # Centraal: dutch main station (Hbf in .nl) # HB: swiss main station (Hbf in .ch) # hl.n.: czech main station (Hbf in .cz) if ( $stop =~ m{ HB $ | hl\.n\. $ | Hbf | Centraal | Flughafen }x ) { return 1; } return; } ); $self->helper( 'json_route_diff' => sub { my ( $self, $route, $sched_route ) = @_; my @json_route; my @route = @{$route}; my @sched_route = @{$sched_route}; my $route_idx = 0; my $sched_idx = 0; while ( $route_idx <= $#route and $sched_idx <= $#sched_route ) { if ( $route[$route_idx] eq $sched_route[$sched_idx] ) { push( @json_route, { name => $route[$route_idx] } ); $route_idx++; $sched_idx++; } # this branch is inefficient, but won't be taken frequently elsif ( not( $route[$route_idx] ~~ \@sched_route ) ) { push( @json_route, { name => $route[$route_idx], isAdditional => 1 } ); $route_idx++; } else { push( @json_route, { name => $sched_route[$sched_idx], isCancelled => 1 } ); $sched_idx++; } } while ( $route_idx < $#route ) { push( @json_route, { name => $route[$route_idx], isAdditional => 1, isCancelled => 0 } ); $route_idx++; } while ( $sched_idx < $#sched_route ) { push( @json_route, { name => $sched_route[$sched_idx], isAdditional => 0, isCancelled => 1 } ); $sched_idx++; } return @json_route; } ); my $r = $self->routes; $r->get('/_redirect')->to('static#redirect'); $r->get('/_auto')->to('static#geolocation'); $r->get('/_datenschutz')->to('static#privacy'); $r->post('/_geolocation')->to('stationboard#stations_by_coordinates'); $r->get('/_about')->to('static#about'); $r->get('/_impressum')->to('static#imprint'); $r->get('/_wr/:train/:departure')->to('wagenreihung#wagenreihung'); $self->defaults( layout => 'app' ); $self->sessions->default_expiration( 3600 * 24 * 28 ); $r->get('/')->to('stationboard#handle_request'); $r->get('/multi/*station')->to('stationboard#handle_request'); $r->get('/*station')->to('stationboard#handle_request'); $self->config( hypnotoad => { accepts => $ENV{DBFAKEDISPLAY_ACCEPTS} // 100, clients => $ENV{DBFAKEDISPLAY_CLIENTS} // 10, listen => [ $ENV{DBFAKEDISPLAY_LISTEN} // 'http://*:8092' ], pid_file => $ENV{DBFAKEDISPLAY_PID_FILE} // '/tmp/db-fakedisplay.pid', spare => $ENV{DBFAKEDISPLAY_SPARE} // 2, workers => $ENV{DBFAKEDISPLAY_WORKERS} // 2, }, ); $self->types->type( json => 'application/json; charset=utf-8' ); } 1;