use promises for checkin and traewelling_to_travelynx

This commit is contained in:
Birte Kristina Friesel 2023-07-09 14:46:28 +02:00
parent f7e3bb490d
commit 1074f248cc
No known key found for this signature in database
GPG key ID: 19E6E524EBB177BA
4 changed files with 296 additions and 223 deletions

View file

@ -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;
$self->iris->get_departures_p(
station => $station,
lookbehind => 140,
lookahead => 40
)->then(
sub {
my ($status) = @_;
if ( $status->{errstr} ) {
$promise->reject( $status->{errstr} );
return;
}
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;
# Otherwise, someone forgot to check out first
$self->checkout(
station => $station,
force => 1,
uid => $uid,
db => $db
);
}
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} ) {
# mustn't be called during a transaction
$self->add_route_timestamps( $uid, $train, 1 );
$self->run_hook( $uid, 'checkin' );
}
return ( $train, undef );
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;
}
if ( not $err ) {
( undef, $err ) = $self->checkout(
station => $traewelling->{arr_eva},
train_id => 0,
$self->log->debug("... found train: $train_id");
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;
}
);

View file

@ -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
);

View file

@ -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} );

View file

@ -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(