From 1074f248cc415a397f16d0328a8f45fa6a867513 Mon Sep 17 00:00:00 2001 From: Birte Kristina Friesel Date: Sun, 9 Jul 2023 14:46:28 +0200 Subject: use promises for checkin and traewelling_to_travelynx --- lib/Travelynx.pm | 327 ++++++++++++++++++++-------------- lib/Travelynx/Command/traewelling.pm | 2 +- lib/Travelynx/Controller/Api.pm | 74 ++++---- lib/Travelynx/Controller/Traveling.pm | 114 ++++++------ 4 files changed, 295 insertions(+), 222 deletions(-) (limited to 'lib') diff --git a/lib/Travelynx.pm b/lib/Travelynx.pm index 6e67237..0dc0f92 100755 --- a/lib/Travelynx.pm +++ b/lib/Travelynx.pm @@ -414,68 +414,87 @@ sub startup { ); $self->helper( - 'checkin' => sub { + 'checkin_p' => sub { my ( $self, %opt ) = @_; my $station = $opt{station}; my $train_id = $opt{train_id}; my $uid = $opt{uid} // $self->current_user->{id}; my $db = $opt{db} // $self->pg->db; + my $hafas; - my $status = $self->iris->get_departures( - station => $station, - lookbehind => 140, - lookahead => 40 - ); - if ( $status->{errstr} ) { - return ( undef, $status->{errstr} ); + if ( $train_id =~ m{[|]} ) { + $hafas = 1; } - my ($train) = List::Util::first { $_->train_id eq $train_id } - @{ $status->{results} }; - if ( not defined $train ) { - return ( undef, "Train ${train_id} not found" ); + if ($hafas) { + return Mojo::Promise->reject( + 'HAFAS checkins are not supported yet, sorry'); } my $user = $self->get_user_status( $uid, $db ); if ( $user->{checked_in} or $user->{cancelled} ) { + return Mojo::Promise->reject('You are already checked in'); + } - if ( $user->{train_id} eq $train_id - and $user->{dep_eva} eq $status->{station_eva} ) - { - # checking in twice is harmless - return ( $train, undef ); - } + my $promise = Mojo::Promise->new; - # Otherwise, someone forgot to check out first - $self->checkout( - station => $station, - force => 1, - uid => $uid, - db => $db - ); - } + $self->iris->get_departures_p( + station => $station, + lookbehind => 140, + lookahead => 40 + )->then( + sub { + my ($status) = @_; - eval { - $self->in_transit->add( - uid => $uid, - db => $db, - departure_eva => $status->{station_eva}, - train => $train, - route => [ $self->iris->route_diff($train) ], - ); - }; - if ($@) { - $self->app->log->error("Checkin($uid): INSERT failed: $@"); - return ( undef, 'INSERT failed: ' . $@ ); - } - if ( not $opt{in_transaction} ) { + if ( $status->{errstr} ) { + $promise->reject( $status->{errstr} ); + return; + } - # mustn't be called during a transaction - $self->add_route_timestamps( $uid, $train, 1 ); - $self->run_hook( $uid, 'checkin' ); - } - return ( $train, undef ); + my $eva = $status->{station_eva}; + my $train = List::Util::first { $_->train_id eq $train_id } + @{ $status->{results} }; + + if ( not defined $train ) { + $promise->reject("Train ${train_id} not found"); + return; + } + + eval { + $self->in_transit->add( + uid => $uid, + db => $db, + departure_eva => $eva, + train => $train, + route => [ $self->iris->route_diff($train) ], + ); + }; + if ($@) { + $self->app->log->error( + "Checkin($uid): INSERT failed: $@"); + $promise->reject( 'INSERT failed: ' . $@ ); + return; + } + + # mustn't be called during a transaction + if ( not $opt{in_transaction} ) { + $self->add_route_timestamps( $uid, $train, 1 ); + $self->run_hook( $uid, 'checkin' ); + } + + $promise->resolve($train); + return; + } + )->catch( + sub { + my ($status) = @_; + $promise->reject( $status->{errstr} ); + return; + } + )->wait; + + return $promise; } ); @@ -1814,17 +1833,19 @@ sub startup { ); $self->helper( - 'traewelling_to_travelynx' => sub { + 'traewelling_to_travelynx_p' => sub { my ( $self, %opt ) = @_; my $traewelling = $opt{traewelling}; my $user_data = $opt{user_data}; my $uid = $user_data->{user_id}; + my $promise = Mojo::Promise->new; + if ( not $traewelling->{checkin} or $self->now->epoch - $traewelling->{checkin}->epoch > 900 ) { $self->log->debug("... not checked in"); - return; + return $promise->resolve; } if ( $traewelling->{status_id} and $user_data->{data}{latest_pull_status_id} @@ -1832,7 +1853,7 @@ sub startup { == $user_data->{data}{latest_pull_status_id} ) { $self->log->debug("... already handled"); - return; + return $promise->resolve; } $self->log->debug( "... checked in : $traewelling->{dep_name} $traewelling->{dep_eva} -> $traewelling->{arr_name} $traewelling->{arr_eva}" @@ -1841,7 +1862,7 @@ sub startup { if ( $user_status->{checked_in} ) { $self->log->debug( "... also checked in via travelynx. aborting."); - return; + return $promise->resolve; } if ( $traewelling->{category} @@ -1859,115 +1880,149 @@ sub startup { uid => $uid, status_id => $traewelling->{status_id} ); - return; + return $promise->resolve; } - my $dep = $self->iris->get_departures( + $self->iris->get_departures_p( station => $traewelling->{dep_eva}, lookbehind => 60, lookahead => 40 - ); - if ( $dep->{errstr} ) { - $self->traewelling->log( - uid => $uid, - message => + )->then( + sub { + my ($dep) = @_; + my ( $train_ref, $train_id ); + + if ( $dep->{errstr} ) { + $self->traewelling->log( + uid => $uid, + message => "Konnte $traewelling->{line} nach $traewelling->{arr_name} nicht übernehmen: $dep->{errstr}", - status_id => $traewelling->{status_id}, - is_error => 1, - ); - return; - } - my ( $train_ref, $train_id ); - for my $train ( @{ $dep->{results} } ) { - if ( $train->line ne $traewelling->{line} ) { - next; - } - if ( not $train->sched_departure - or $train->sched_departure->epoch - != $traewelling->{dep_dt}->epoch ) - { - next; - } - if ( - not List::Util::first { $_ eq $traewelling->{arr_name} } - $train->route_post - ) - { - next; - } - $train_id = $train->train_id; - $train_ref = $train; - last; - } - if ($train_id) { - $self->log->debug("... found train: $train_id"); + status_id => $traewelling->{status_id}, + is_error => 1, + ); + $promise->resolve; + return; + } - my $db = $self->pg->db; - my $tx = $db->begin; + for my $train ( @{ $dep->{results} } ) { + if ( $train->line ne $traewelling->{line} ) { + next; + } + if ( not $train->sched_departure + or $train->sched_departure->epoch + != $traewelling->{dep_dt}->epoch ) + { + next; + } + if ( + not + List::Util::first { $_ eq $traewelling->{arr_name} } + $train->route_post + ) + { + next; + } + $train_id = $train->train_id; + $train_ref = $train; + last; + } - my ( undef, $err ) = $self->checkin( - station => $traewelling->{dep_eva}, - train_id => $train_id, - uid => $uid, - in_transaction => 1, - db => $db - ); + if ( not $train_id ) { + $self->log->debug( + "... train $traewelling->{line} not found"); + $self->traewelling->log( + uid => $uid, + message => +"Konnte $traewelling->{line} nach $traewelling->{arr_name} nicht übernehmen: Zug nicht gefunden", + status_id => $traewelling->{status_id}, + is_error => 1 + ); + return $promise->resolve; + } + + $self->log->debug("... found train: $train_id"); - if ( not $err ) { - ( undef, $err ) = $self->checkout( - station => $traewelling->{arr_eva}, - train_id => 0, + my $db = $self->pg->db; + my $tx = $db->begin; + + $self->checkin_p( + station => $traewelling->{dep_eva}, + train_id => $train_id, uid => $uid, in_transaction => 1, db => $db - ); - if ( not $err ) { - $self->log->debug("... success!"); - if ( $traewelling->{message} ) { - $self->in_transit->update_user_data( - uid => $uid, - db => $db, - user_data => - { comment => $traewelling->{message} } + )->then( + sub { + $self->log->debug("... handled origin"); + my ( undef, $err ) = $self->checkout( + station => $traewelling->{arr_eva}, + train_id => 0, + uid => $uid, + in_transaction => 1, + db => $db ); - } - $self->traewelling->log( - uid => $uid, - db => $db, - message => + if ($err) { + $self->log->debug("... error: $err"); + return Mojo::Promise->reject($err); + } + $self->log->debug("... handled destination"); + if ( $traewelling->{message} ) { + $self->in_transit->update_user_data( + uid => $uid, + db => $db, + user_data => + { comment => $traewelling->{message} } + ); + } + $self->traewelling->log( + uid => $uid, + db => $db, + message => "Eingecheckt in $traewelling->{line} nach $traewelling->{arr_name}", - status_id => $traewelling->{status_id}, - ); - $self->traewelling->set_latest_pull_status_id( - uid => $uid, - status_id => $traewelling->{status_id}, - db => $db - ); + status_id => $traewelling->{status_id}, + ); + $self->traewelling->set_latest_pull_status_id( + uid => $uid, + status_id => $traewelling->{status_id}, + db => $db + ); - $tx->commit; - } + $tx->commit; + $promise->resolve; + return; + } + )->catch( + sub { + my ($err) = @_; + $self->log->debug("... error: $err"); + $self->traewelling->log( + uid => $uid, + message => +"Konnte $traewelling->{line} nach $traewelling->{arr_name} nicht übernehmen: $err", + status_id => $traewelling->{status_id}, + is_error => 1 + ); + $promise->resolve; + return; + } + )->wait; } - if ($err) { - $self->log->debug("... error: $err"); + )->catch( + sub { + my ($dep) = @_; $self->traewelling->log( uid => $uid, message => -"Konnte $traewelling->{line} nach $traewelling->{arr_name} nicht übernehmen: $err", +"Konnte $traewelling->{line} nach $traewelling->{arr_name} nicht übernehmen: $dep->{errstr}", status_id => $traewelling->{status_id}, - is_error => 1 + is_error => 1, ); + $promise->resolve; + return; } - } - else { - $self->log->debug("... train $traewelling->{line} not found"); - $self->traewelling->log( - uid => $uid, - message => -"Konnte $traewelling->{line} nach $traewelling->{arr_name} nicht übernehmen: Zug nicht gefunden", - status_id => $traewelling->{status_id}, - is_error => 1 - ); - } + )->wait; + + return $promise; } ); diff --git a/lib/Travelynx/Command/traewelling.pm b/lib/Travelynx/Command/traewelling.pm index 1974352..4c47e84 100644 --- a/lib/Travelynx/Command/traewelling.pm +++ b/lib/Travelynx/Command/traewelling.pm @@ -50,7 +50,7 @@ sub pull_sync { sub { my ($traewelling) = @_; $pull_result{ $traewelling->{http} } += 1; - $self->app->traewelling_to_travelynx( + return $self->app->traewelling_to_travelynx_p( traewelling => $traewelling, user_data => $account_data ); diff --git a/lib/Travelynx/Controller/Api.pm b/lib/Travelynx/Controller/Api.pm index ac436ba..fbccbaa 100755 --- a/lib/Travelynx/Controller/Api.pm +++ b/lib/Travelynx/Controller/Api.pm @@ -261,43 +261,53 @@ sub travel_v1 { $train_id = $train->train_id; } - my ( $train, $error ) = $self->checkin( + $self->render_later; + + $self->checkin_p( station => $from_station, train_id => $train_id, uid => $uid - ); - if ( $payload->{comment} and not $error ) { - $self->in_transit->update_user_data( - uid => $uid, - user_data => { comment => sanitize( q{}, $payload->{comment} ) } - ); - } - if ( $to_station and not $error ) { - ( $train, $error ) = $self->checkout( - station => $to_station, - force => 0, - uid => $uid - ); - } - if ($error) { - $self->render( - json => { - success => \0, - deprecated => \0, - error => 'Checkin/Checkout error: ' . $error, - status => $self->get_user_status_json_v1( uid => $uid ) + )->then( + sub { + my ($train) = @_; + if ( $payload->{comment} ) { + $self->in_transit->update_user_data( + uid => $uid, + user_data => + { comment => sanitize( q{}, $payload->{comment} ) } + ); } - ); - } - else { - $self->render( - json => { - success => \1, - deprecated => \0, - status => $self->get_user_status_json_v1( uid => $uid ) + if ($to_station) { + my ( $train2, $error ) = $self->checkout( + station => $to_station, + force => 0, + uid => $uid + ); + if ($error) { + return Mojo::Promise->reject($error); + } } - ); - } + $self->render( + json => { + success => \1, + deprecated => \0, + status => $self->get_user_status_json_v1( uid => $uid ) + } + ); + } + )->catch( + sub { + my ($error) = @_; + $self->render( + json => { + success => \0, + deprecated => \0, + error => 'Checkin/Checkout error: ' . $error, + status => $self->get_user_status_json_v1( uid => $uid ) + } + ); + } + )->wait; } elsif ( $payload->{action} eq 'checkout' ) { my $to_station = sanitize( q{}, $payload->{toStation} ); diff --git a/lib/Travelynx/Controller/Traveling.pm b/lib/Travelynx/Controller/Traveling.pm index 7c2fe33..96acdd2 100755 --- a/lib/Travelynx/Controller/Traveling.pm +++ b/lib/Travelynx/Controller/Traveling.pm @@ -615,43 +615,48 @@ sub travel_action { if ( $params->{action} eq 'checkin' ) { - my ( $train, $error ) = $self->checkin( + $self->render_later; + $self->checkin_p( station => $params->{station}, train_id => $params->{train} - ); - my $destination = $params->{dest}; + )->then( + sub { + my $destination = $params->{dest}; + if ( not $destination ) { + $self->render( + json => { + success => 1, + redirect_to => '/', + }, + ); + return; + } - if ($error) { - $self->render( - json => { - success => 0, - error => $error, - }, - ); - } - elsif ( not $destination ) { - $self->render( - json => { - success => 1, - redirect_to => '/', - }, - ); - } - else { - # Silently ignore errors -- if they are permanent, the user will see - # them when selecting the destination manually. - my ( $still_checked_in, undef ) = $self->checkout( - station => $destination, - force => 0 - ); - my $station_link = '/s/' . $destination; - $self->render( - json => { - success => 1, - redirect_to => $still_checked_in ? '/' : $station_link, - }, - ); - } + # Silently ignore errors -- if they are permanent, the user will see + # them when selecting the destination manually. + my ( $still_checked_in, undef ) = $self->checkout( + station => $destination, + force => 0 + ); + my $station_link = '/s/' . $destination; + $self->render( + json => { + success => 1, + redirect_to => $still_checked_in ? '/' : $station_link, + }, + ); + } + )->catch( + sub { + my ($error) = @_; + $self->render( + json => { + success => 0, + error => $error, + }, + ); + } + )->wait; } elsif ( $params->{action} eq 'checkout' ) { my ( $still_checked_in, $error ) = $self->checkout( @@ -702,27 +707,30 @@ sub travel_action { } } elsif ( $params->{action} eq 'cancelled_from' ) { - my ( undef, $error ) = $self->checkin( + $self->render_later; + $self->checkin_p( station => $params->{station}, train_id => $params->{train} - ); - - if ($error) { - $self->render( - json => { - success => 0, - error => $error, - }, - ); - } - else { - $self->render( - json => { - success => 1, - redirect_to => '/', - }, - ); - } + )->then( + sub { + $self->render( + json => { + success => 1, + redirect_to => '/', + }, + ); + } + )->catch( + sub { + my ($error) = @_; + $self->render( + json => { + success => 0, + error => $error, + }, + ); + } + )->wait; } elsif ( $params->{action} eq 'cancelled_to' ) { my ( undef, $error ) = $self->checkout( -- cgit v1.2.3