convert checkout to promises (checkout_p)
This commit is contained in:
parent
c0754f9e87
commit
38ad42b42c
3 changed files with 347 additions and 256 deletions
125
lib/Travelynx.pm
125
lib/Travelynx.pm
|
@ -588,7 +588,7 @@ sub startup {
|
||||||
);
|
);
|
||||||
|
|
||||||
$self->helper(
|
$self->helper(
|
||||||
'checkout' => sub {
|
'checkout_p' => sub {
|
||||||
my ( $self, %opt ) = @_;
|
my ( $self, %opt ) = @_;
|
||||||
|
|
||||||
my $station = $opt{station};
|
my $station = $opt{station};
|
||||||
|
@ -596,34 +596,29 @@ sub startup {
|
||||||
my $arr_eva = $opt{arr_eva};
|
my $arr_eva = $opt{arr_eva};
|
||||||
my $with_related = $opt{with_related} // 0;
|
my $with_related = $opt{with_related} // 0;
|
||||||
my $force = $opt{force};
|
my $force = $opt{force};
|
||||||
my $uid = $opt{uid};
|
my $uid = $opt{uid} // $self->current_user->{id};
|
||||||
my $db = $opt{db} // $self->pg->db;
|
my $db = $opt{db} // $self->pg->db;
|
||||||
my $status = $self->iris->get_departures(
|
|
||||||
station => $station,
|
|
||||||
lookbehind => 120,
|
|
||||||
lookahead => 180,
|
|
||||||
with_related => $with_related,
|
|
||||||
);
|
|
||||||
$uid //= $self->current_user->{id};
|
|
||||||
my $user = $self->get_user_status( $uid, $db );
|
my $user = $self->get_user_status( $uid, $db );
|
||||||
my $train_id = $user->{train_id};
|
my $train_id = $user->{train_id};
|
||||||
|
|
||||||
|
my $promise = Mojo::Promise->new;
|
||||||
|
|
||||||
if ( not $station ) {
|
if ( not $station ) {
|
||||||
$self->app->log->error("Checkout($uid): station is empty");
|
$self->app->log->error("Checkout($uid): station is empty");
|
||||||
return ( 1, 'BUG: Checkout station is empty.' );
|
return $promise->resolve( 1,
|
||||||
|
'BUG: Checkout station is empty.' );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( not $user->{checked_in} and not $user->{cancelled} ) {
|
if ( not $user->{checked_in} and not $user->{cancelled} ) {
|
||||||
return ( 0, 'You are not checked into any train' );
|
return $promise->resolve( 0,
|
||||||
}
|
'You are not checked into any train' );
|
||||||
if ( $status->{errstr} and not $force ) {
|
|
||||||
return ( 1, $status->{errstr} );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $dep_eva and $dep_eva != $user->{dep_eva} ) {
|
if ( $dep_eva and $dep_eva != $user->{dep_eva} ) {
|
||||||
return ( 0, 'race condition' );
|
return $promise->resolve( 0, 'race condition' );
|
||||||
}
|
}
|
||||||
if ( $arr_eva and $arr_eva != $user->{arr_eva} ) {
|
if ( $arr_eva and $arr_eva != $user->{arr_eva} ) {
|
||||||
return ( 0, 'race condition' );
|
return $promise->resolve( 0, 'race condition' );
|
||||||
}
|
}
|
||||||
|
|
||||||
my $now = DateTime->now( time_zone => 'Europe/Berlin' );
|
my $now = DateTime->now( time_zone => 'Europe/Berlin' );
|
||||||
|
@ -632,23 +627,21 @@ sub startup {
|
||||||
with_data => 1
|
with_data => 1
|
||||||
);
|
);
|
||||||
|
|
||||||
# Note that a train may pass the same station several times.
|
$self->iris->get_departures_p(
|
||||||
# Notable example: S41 / S42 ("Ringbahn") both starts and
|
station => $station,
|
||||||
# terminates at Berlin Südkreuz
|
lookbehind => 120,
|
||||||
my ($train) = List::Util::first {
|
lookahead => 180,
|
||||||
$_->train_id eq $train_id
|
with_related => $with_related,
|
||||||
and $_->sched_arrival
|
)->then(
|
||||||
and $_->sched_arrival->epoch > $user->{sched_departure}->epoch
|
sub {
|
||||||
}
|
my ($status) = @_;
|
||||||
@{ $status->{results} };
|
|
||||||
|
|
||||||
$train //= List::Util::first { $_->train_id eq $train_id }
|
|
||||||
@{ $status->{results} };
|
|
||||||
|
|
||||||
my $new_checkout_station_id = $status->{station_eva};
|
my $new_checkout_station_id = $status->{station_eva};
|
||||||
|
|
||||||
# Store the intended checkout station regardless of this operation's
|
# Store the intended checkout station regardless of this operation's
|
||||||
# success.
|
# success.
|
||||||
|
# TODO for with_related == 1, the correct EVA may be different
|
||||||
|
# and should be fetched from $train later on
|
||||||
$self->in_transit->set_arrival_eva(
|
$self->in_transit->set_arrival_eva(
|
||||||
uid => $uid,
|
uid => $uid,
|
||||||
db => $db,
|
db => $db,
|
||||||
|
@ -667,10 +660,24 @@ sub startup {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Note that a train may pass the same station several times.
|
||||||
|
# Notable example: S41 / S42 ("Ringbahn") both starts and
|
||||||
|
# terminates at Berlin Südkreuz
|
||||||
|
my $train = List::Util::first {
|
||||||
|
$_->train_id eq $train_id
|
||||||
|
and $_->sched_arrival
|
||||||
|
and $_->sched_arrival->epoch
|
||||||
|
> $user->{sched_departure}->epoch
|
||||||
|
}
|
||||||
|
@{ $status->{results} };
|
||||||
|
|
||||||
|
$train //= List::Util::first { $_->train_id eq $train_id }
|
||||||
|
@{ $status->{results} };
|
||||||
|
|
||||||
if ( not defined $train ) {
|
if ( not defined $train ) {
|
||||||
|
|
||||||
# Arrival time via IRIS is unknown, so the train probably has not
|
# Arrival time via IRIS is unknown, so the train probably
|
||||||
# arrived yet. Fall back to HAFAS.
|
# has not arrived yet. Fall back to HAFAS.
|
||||||
# TODO support cases where $station is EVA or DS100 code
|
# TODO support cases where $station is EVA or DS100 code
|
||||||
if (
|
if (
|
||||||
my $station_data
|
my $station_data
|
||||||
|
@ -682,14 +689,16 @@ sub startup {
|
||||||
if ( $station_data->{sched_arr} ) {
|
if ( $station_data->{sched_arr} ) {
|
||||||
my $sched_arr
|
my $sched_arr
|
||||||
= epoch_to_dt( $station_data->{sched_arr} );
|
= epoch_to_dt( $station_data->{sched_arr} );
|
||||||
my $rt_arr = epoch_to_dt( $station_data->{rt_arr} );
|
my $rt_arr
|
||||||
|
= epoch_to_dt( $station_data->{rt_arr} );
|
||||||
if ( $rt_arr->epoch == 0 ) {
|
if ( $rt_arr->epoch == 0 ) {
|
||||||
$rt_arr = $sched_arr->clone;
|
$rt_arr = $sched_arr->clone;
|
||||||
if ( $station_data->{arr_delay}
|
if ( $station_data->{arr_delay}
|
||||||
and $station_data->{arr_delay} =~ m{^\d+$} )
|
and $station_data->{arr_delay}
|
||||||
|
=~ m{^\d+$} )
|
||||||
{
|
{
|
||||||
$rt_arr->add(
|
$rt_arr->add( minutes =>
|
||||||
minutes => $station_data->{arr_delay} );
|
$station_data->{arr_delay} );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$self->in_transit->set_arrival_times(
|
$self->in_transit->set_arrival_times(
|
||||||
|
@ -706,10 +715,10 @@ sub startup {
|
||||||
if ( not $opt{in_transaction} ) {
|
if ( not $opt{in_transaction} ) {
|
||||||
$self->run_hook( $uid, 'update' );
|
$self->run_hook( $uid, 'update' );
|
||||||
}
|
}
|
||||||
return ( 1, undef );
|
$promise->resolve( 1, undef );
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
my $has_arrived = 0;
|
my $has_arrived = 0;
|
||||||
|
|
||||||
eval {
|
eval {
|
||||||
|
@ -719,7 +728,10 @@ sub startup {
|
||||||
$tx = $db->begin;
|
$tx = $db->begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( defined $train and not $train->arrival and not $force ) {
|
if ( defined $train
|
||||||
|
and not $train->arrival
|
||||||
|
and not $force )
|
||||||
|
{
|
||||||
my $train_no = $train->train_no;
|
my $train_no = $train->train_no;
|
||||||
die("Train ${train_no} has no arrival timestamp\n");
|
die("Train ${train_no} has no arrival timestamp\n");
|
||||||
}
|
}
|
||||||
|
@ -731,10 +743,12 @@ sub startup {
|
||||||
route => [ $self->iris->route_diff($train) ]
|
route => [ $self->iris->route_diff($train) ]
|
||||||
);
|
);
|
||||||
|
|
||||||
$has_arrived = $train->arrival->epoch < $now->epoch ? 1 : 0;
|
$has_arrived
|
||||||
|
= $train->arrival->epoch < $now->epoch ? 1 : 0;
|
||||||
if ($has_arrived) {
|
if ($has_arrived) {
|
||||||
my @unknown_stations
|
my @unknown_stations
|
||||||
= $self->stations->grep_unknown( $train->route );
|
= $self->stations->grep_unknown(
|
||||||
|
$train->route );
|
||||||
if (@unknown_stations) {
|
if (@unknown_stations) {
|
||||||
$self->app->log->warn(
|
$self->app->log->warn(
|
||||||
sprintf(
|
sprintf(
|
||||||
|
@ -767,7 +781,8 @@ sub startup {
|
||||||
|
|
||||||
my $cache_ts = $now->clone;
|
my $cache_ts = $now->clone;
|
||||||
if ( $journey->{real_departure}
|
if ( $journey->{real_departure}
|
||||||
=~ m{ ^ (?<year> \d{4} ) - (?<month> \d{2} ) }x )
|
=~ m{ ^ (?<year> \d{4} ) - (?<month> \d{2} ) }x
|
||||||
|
)
|
||||||
{
|
{
|
||||||
$cache_ts->set(
|
$cache_ts->set(
|
||||||
year => $+{year},
|
year => $+{year},
|
||||||
|
@ -780,7 +795,9 @@ sub startup {
|
||||||
uid => $uid
|
uid => $uid
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
elsif ( defined $train and $train->arrival_is_cancelled ) {
|
elsif ( defined $train
|
||||||
|
and $train->arrival_is_cancelled )
|
||||||
|
{
|
||||||
|
|
||||||
# This branch is only taken if the deparure was not cancelled,
|
# This branch is only taken if the deparure was not cancelled,
|
||||||
# i.e., if the train was supposed to go here but got
|
# i.e., if the train was supposed to go here but got
|
||||||
|
@ -808,20 +825,34 @@ sub startup {
|
||||||
|
|
||||||
if ($@) {
|
if ($@) {
|
||||||
$self->app->log->error("Checkout($uid): $@");
|
$self->app->log->error("Checkout($uid): $@");
|
||||||
return ( 1, 'Checkout error: ' . $@ );
|
$promise->resolve( 1, 'Checkout error: ' . $@ );
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $has_arrived or $force ) {
|
if ( $has_arrived or $force ) {
|
||||||
if ( not $opt{in_transaction} ) {
|
if ( not $opt{in_transaction} ) {
|
||||||
$self->run_hook( $uid, 'checkout' );
|
$self->run_hook( $uid, 'checkout' );
|
||||||
}
|
}
|
||||||
return ( 0, undef );
|
$promise->resolve( 0, undef );
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if ( not $opt{in_transaction} ) {
|
if ( not $opt{in_transaction} ) {
|
||||||
$self->run_hook( $uid, 'update' );
|
$self->run_hook( $uid, 'update' );
|
||||||
$self->add_route_timestamps( $uid, $train, 0, 1 );
|
$self->add_route_timestamps( $uid, $train, 0, 1 );
|
||||||
}
|
}
|
||||||
return ( 1, undef );
|
$promise->resolve( 1, undef );
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
)->catch(
|
||||||
|
sub {
|
||||||
|
my ($err) = @_;
|
||||||
|
$promise->resolve( 1, $err );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
)->wait;
|
||||||
|
|
||||||
|
return $promise;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1788,13 +1819,17 @@ sub startup {
|
||||||
)->then(
|
)->then(
|
||||||
sub {
|
sub {
|
||||||
$self->log->debug("... handled origin");
|
$self->log->debug("... handled origin");
|
||||||
my ( undef, $err ) = $self->checkout(
|
return $self->checkout_p(
|
||||||
station => $traewelling->{arr_eva},
|
station => $traewelling->{arr_eva},
|
||||||
train_id => 0,
|
train_id => 0,
|
||||||
uid => $uid,
|
uid => $uid,
|
||||||
in_transaction => 1,
|
in_transaction => 1,
|
||||||
db => $db
|
db => $db
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
)->then(
|
||||||
|
sub {
|
||||||
|
my ( undef, $err ) = @_;
|
||||||
if ($err) {
|
if ($err) {
|
||||||
$self->log->debug("... error: $err");
|
$self->log->debug("... error: $err");
|
||||||
return Mojo::Promise->reject($err);
|
return Mojo::Promise->reject($err);
|
||||||
|
|
|
@ -88,13 +88,13 @@ sub run {
|
||||||
|
|
||||||
# check out (adds a cancelled journey and resets journey state
|
# check out (adds a cancelled journey and resets journey state
|
||||||
# to checkin
|
# to checkin
|
||||||
$self->app->checkout(
|
$self->app->checkout_p(
|
||||||
station => $arr,
|
station => $arr,
|
||||||
force => 1,
|
force => 2,
|
||||||
dep_eva => $dep,
|
dep_eva => $dep,
|
||||||
arr_eva => $arr,
|
arr_eva => $arr,
|
||||||
uid => $uid
|
uid => $uid
|
||||||
);
|
)->wait;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -155,13 +155,13 @@ sub run {
|
||||||
|
|
||||||
# check out (adds a cancelled journey and resets journey state
|
# check out (adds a cancelled journey and resets journey state
|
||||||
# to destination selection)
|
# to destination selection)
|
||||||
$self->app->checkout(
|
$self->app->checkout_p(
|
||||||
station => $arr,
|
station => $arr,
|
||||||
force => 0,
|
force => 0,
|
||||||
dep_eva => $dep,
|
dep_eva => $dep,
|
||||||
arr_eva => $arr,
|
arr_eva => $arr,
|
||||||
uid => $uid
|
uid => $uid
|
||||||
);
|
)->wait;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$self->app->add_route_timestamps(
|
$self->app->add_route_timestamps(
|
||||||
|
@ -174,21 +174,24 @@ sub run {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elsif ( $entry->{real_arr_ts} ) {
|
elsif ( $entry->{real_arr_ts} ) {
|
||||||
my ( undef, $error ) = $self->app->checkout(
|
my ( undef, $error ) = $self->app->checkout_p(
|
||||||
station => $arr,
|
station => $arr,
|
||||||
force => 1,
|
force => 2,
|
||||||
dep_eva => $dep,
|
dep_eva => $dep,
|
||||||
arr_eva => $arr,
|
arr_eva => $arr,
|
||||||
uid => $uid
|
uid => $uid
|
||||||
);
|
)->catch(
|
||||||
if ($error) {
|
sub {
|
||||||
die("${error}\n");
|
my ($error) = @_;
|
||||||
|
$self->app->log->error("work($uid)/arrival: $@");
|
||||||
|
$errors += 1;
|
||||||
}
|
}
|
||||||
|
)->wait;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if ($@) {
|
if ($@) {
|
||||||
$errors += 1;
|
|
||||||
$self->app->log->error("work($uid)/arrival: $@");
|
$self->app->log->error("work($uid)/arrival: $@");
|
||||||
|
$errors += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
eval { }
|
eval { }
|
||||||
|
|
|
@ -622,17 +622,26 @@ sub travel_action {
|
||||||
if ( $params->{action} eq 'checkin' ) {
|
if ( $params->{action} eq 'checkin' ) {
|
||||||
|
|
||||||
my $status = $self->get_user_status;
|
my $status = $self->get_user_status;
|
||||||
|
my $promise;
|
||||||
|
|
||||||
if ( $status->{checked_in}
|
if ( $status->{checked_in}
|
||||||
and $status->{arr_eva}
|
and $status->{arr_eva}
|
||||||
and $status->{arrival_countdown} <= 0 )
|
and $status->{arrival_countdown} <= 0 )
|
||||||
{
|
{
|
||||||
$self->checkout( station => $status->{arr_eva} );
|
$promise = $self->checkout_p( station => $status->{arr_eva} );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$promise = Mojo::Promise->resolve;
|
||||||
}
|
}
|
||||||
|
|
||||||
$self->render_later;
|
$self->render_later;
|
||||||
$self->checkin_p(
|
$promise->then(
|
||||||
|
sub {
|
||||||
|
return $self->checkin_p(
|
||||||
station => $params->{station},
|
station => $params->{station},
|
||||||
train_id => $params->{train}
|
train_id => $params->{train}
|
||||||
|
);
|
||||||
|
}
|
||||||
)->then(
|
)->then(
|
||||||
sub {
|
sub {
|
||||||
my $destination = $params->{dest};
|
my $destination = $params->{dest};
|
||||||
|
@ -648,18 +657,27 @@ sub travel_action {
|
||||||
|
|
||||||
# Silently ignore errors -- if they are permanent, the user will see
|
# Silently ignore errors -- if they are permanent, the user will see
|
||||||
# them when selecting the destination manually.
|
# them when selecting the destination manually.
|
||||||
my ( $still_checked_in, undef ) = $self->checkout(
|
return $self->checkout_p(
|
||||||
station => $destination,
|
station => $destination,
|
||||||
force => 0
|
force => 0
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
)->then(
|
||||||
|
sub {
|
||||||
|
my ( $still_checked_in, undef ) = @_;
|
||||||
|
if ( my $destination = $params->{dest} ) {
|
||||||
my $station_link = '/s/' . $destination;
|
my $station_link = '/s/' . $destination;
|
||||||
$self->render(
|
$self->render(
|
||||||
json => {
|
json => {
|
||||||
success => 1,
|
success => 1,
|
||||||
redirect_to => $still_checked_in ? '/' : $station_link,
|
redirect_to => $still_checked_in
|
||||||
|
? '/'
|
||||||
|
: $station_link,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
)->catch(
|
)->catch(
|
||||||
sub {
|
sub {
|
||||||
my ($error) = @_;
|
my ($error) = @_;
|
||||||
|
@ -673,10 +691,13 @@ sub travel_action {
|
||||||
)->wait;
|
)->wait;
|
||||||
}
|
}
|
||||||
elsif ( $params->{action} eq 'checkout' ) {
|
elsif ( $params->{action} eq 'checkout' ) {
|
||||||
my ( $still_checked_in, $error ) = $self->checkout(
|
$self->render_later;
|
||||||
|
$self->checkout_p(
|
||||||
station => $params->{station},
|
station => $params->{station},
|
||||||
force => $params->{force}
|
force => $params->{force}
|
||||||
);
|
)->then(
|
||||||
|
sub {
|
||||||
|
my ( $still_checked_in, $error ) = @_;
|
||||||
my $station_link = '/s/' . $params->{station};
|
my $station_link = '/s/' . $params->{station};
|
||||||
|
|
||||||
if ($error) {
|
if ($error) {
|
||||||
|
@ -691,10 +712,26 @@ sub travel_action {
|
||||||
$self->render(
|
$self->render(
|
||||||
json => {
|
json => {
|
||||||
success => 1,
|
success => 1,
|
||||||
redirect_to => $still_checked_in ? '/' : $station_link,
|
redirect_to => $still_checked_in
|
||||||
|
? '/'
|
||||||
|
: $station_link,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
)->catch(
|
||||||
|
sub {
|
||||||
|
my ($error) = @_;
|
||||||
|
$self->render(
|
||||||
|
json => {
|
||||||
|
success => 0,
|
||||||
|
error => $error,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
)->wait;
|
||||||
}
|
}
|
||||||
elsif ( $params->{action} eq 'undo' ) {
|
elsif ( $params->{action} eq 'undo' ) {
|
||||||
my $status = $self->get_user_status;
|
my $status = $self->get_user_status;
|
||||||
|
@ -747,11 +784,13 @@ sub travel_action {
|
||||||
)->wait;
|
)->wait;
|
||||||
}
|
}
|
||||||
elsif ( $params->{action} eq 'cancelled_to' ) {
|
elsif ( $params->{action} eq 'cancelled_to' ) {
|
||||||
my ( undef, $error ) = $self->checkout(
|
$self->render_later;
|
||||||
|
$self->checkout_p(
|
||||||
station => $params->{station},
|
station => $params->{station},
|
||||||
force => 1
|
force => 1
|
||||||
);
|
)->then(
|
||||||
|
sub {
|
||||||
|
my ( undef, $error ) = @_;
|
||||||
if ($error) {
|
if ($error) {
|
||||||
$self->render(
|
$self->render(
|
||||||
json => {
|
json => {
|
||||||
|
@ -768,6 +807,20 @@ sub travel_action {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
)->catch(
|
||||||
|
sub {
|
||||||
|
my ($error) = @_;
|
||||||
|
$self->render(
|
||||||
|
json => {
|
||||||
|
success => 0,
|
||||||
|
error => $error,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
)->wait;
|
||||||
}
|
}
|
||||||
elsif ( $params->{action} eq 'delete' ) {
|
elsif ( $params->{action} eq 'delete' ) {
|
||||||
my $error = $self->journeys->delete(
|
my $error = $self->journeys->delete(
|
||||||
|
|
Loading…
Reference in a new issue