Unverified Commit 38ad42b4 authored by Birte Kristina Friesel's avatar Birte Kristina Friesel
Browse files

convert checkout to promises (checkout_p)

parent c0754f9e
Loading
Loading
Loading
Loading
+221 −186
Original line number Diff line number Diff line
@@ -588,7 +588,7 @@ sub startup {
	);

	$self->helper(
		'checkout' => sub {
		'checkout_p' => sub {
			my ( $self, %opt ) = @_;

			my $station      = $opt{station};
@@ -596,34 +596,29 @@ sub startup {
			my $arr_eva      = $opt{arr_eva};
			my $with_related = $opt{with_related} // 0;
			my $force        = $opt{force};
			my $uid          = $opt{uid};
			my $uid          = $opt{uid} // $self->current_user->{id};
			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 $train_id     = $user->{train_id};

			my $promise = Mojo::Promise->new;

			if ( not $station ) {
				$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} ) {
				return ( 0, 'You are not checked into any train' );
			}
			if ( $status->{errstr} and not $force ) {
				return ( 1, $status->{errstr} );
				return $promise->resolve( 0,
					'You are not checked into any train' );
			}

			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} ) {
				return ( 0, 'race condition' );
				return $promise->resolve( 0, 'race condition' );
			}

			my $now     = DateTime->now( time_zone => 'Europe/Berlin' );
@@ -632,23 +627,21 @@ sub startup {
				with_data => 1
			);

			# 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} };
			$self->iris->get_departures_p(
				station      => $station,
				lookbehind   => 120,
				lookahead    => 180,
				with_related => $with_related,
			)->then(
				sub {
					my ($status) = @_;

					my $new_checkout_station_id = $status->{station_eva};

					# Store the intended checkout station regardless of this operation's
					# 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(
						uid         => $uid,
						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 ) {

				# Arrival time via IRIS is unknown, so the train probably has not
				# arrived yet. Fall back to HAFAS.
						# Arrival time via IRIS is unknown, so the train probably
						# has not arrived yet. Fall back to HAFAS.
						# TODO support cases where $station is EVA or DS100 code
						if (
							my $station_data
@@ -682,14 +689,16 @@ sub startup {
							if ( $station_data->{sched_arr} ) {
								my $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 ) {
									$rt_arr = $sched_arr->clone;
									if (    $station_data->{arr_delay}
								and $station_data->{arr_delay} =~ m{^\d+$} )
										and $station_data->{arr_delay}
										=~ m{^\d+$} )
									{
								$rt_arr->add(
									minutes => $station_data->{arr_delay} );
										$rt_arr->add( minutes =>
											  $station_data->{arr_delay} );
									}
								}
								$self->in_transit->set_arrival_times(
@@ -706,10 +715,10 @@ sub startup {
							if ( not $opt{in_transaction} ) {
								$self->run_hook( $uid, 'update' );
							}
					return ( 1, undef );
							$promise->resolve( 1, undef );
							return;
						}
					}

					my $has_arrived = 0;

					eval {
@@ -719,7 +728,10 @@ sub startup {
							$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;
							die("Train ${train_no} has no arrival timestamp\n");
						}
@@ -731,10 +743,12 @@ sub startup {
								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) {
								my @unknown_stations
						  = $self->stations->grep_unknown( $train->route );
								  = $self->stations->grep_unknown(
									$train->route );
								if (@unknown_stations) {
									$self->app->log->warn(
										sprintf(
@@ -767,7 +781,8 @@ sub startup {

							my $cache_ts = $now->clone;
							if ( $journey->{real_departure}
						=~ m{ ^ (?<year> \d{4} ) - (?<month> \d{2} ) }x )
								=~ m{ ^ (?<year> \d{4} ) - (?<month> \d{2} ) }x
							  )
							{
								$cache_ts->set(
									year  => $+{year},
@@ -780,7 +795,9 @@ sub startup {
								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,
							# i.e., if the train was supposed to go here but got
@@ -808,20 +825,34 @@ sub startup {

					if ($@) {
						$self->app->log->error("Checkout($uid): $@");
				return ( 1, 'Checkout error: ' . $@ );
						$promise->resolve( 1, 'Checkout error: ' . $@ );
						return;
					}

					if ( $has_arrived or $force ) {
						if ( not $opt{in_transaction} ) {
							$self->run_hook( $uid, 'checkout' );
						}
				return ( 0, undef );
						$promise->resolve( 0, undef );
						return;
					}
					if ( not $opt{in_transaction} ) {
						$self->run_hook( $uid, 'update' );
						$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(
						sub {
							$self->log->debug("... handled origin");
							my ( undef, $err ) = $self->checkout(
							return $self->checkout_p(
								station        => $traewelling->{arr_eva},
								train_id       => 0,
								uid            => $uid,
								in_transaction => 1,
								db             => $db
							);
						}
					)->then(
						sub {
							my ( undef, $err ) = @_;
							if ($err) {
								$self->log->debug("... error: $err");
								return Mojo::Promise->reject($err);
+19 −16
Original line number Diff line number Diff line
@@ -88,13 +88,13 @@ sub run {

						# check out (adds a cancelled journey and resets journey state
						# to checkin
						$self->app->checkout(
						$self->app->checkout_p(
							station => $arr,
							force   => 1,
							force   => 2,
							dep_eva => $dep,
							arr_eva => $arr,
							uid     => $uid
						);
						)->wait;
					}
				}
				else {
@@ -155,13 +155,13 @@ sub run {

					# check out (adds a cancelled journey and resets journey state
					# to destination selection)
					$self->app->checkout(
					$self->app->checkout_p(
						station => $arr,
						force   => 0,
						dep_eva => $dep,
						arr_eva => $arr,
						uid     => $uid
					);
					)->wait;
				}
				else {
					$self->app->add_route_timestamps(
@@ -174,21 +174,24 @@ sub run {
				}
			}
			elsif ( $entry->{real_arr_ts} ) {
				my ( undef, $error ) = $self->app->checkout(
				my ( undef, $error ) = $self->app->checkout_p(
					station => $arr,
					force   => 1,
					force   => 2,
					dep_eva => $dep,
					arr_eva => $arr,
					uid     => $uid
				);
				if ($error) {
					die("${error}\n");
				)->catch(
					sub {
						my ($error) = @_;
						$self->app->log->error("work($uid)/arrival: $@");
						$errors += 1;
					}
				)->wait;
			}
		};
		if ($@) {
			$errors += 1;
			$self->app->log->error("work($uid)/arrival: $@");
			$errors += 1;
		}

		eval { }
+103 −50
Original line number Diff line number Diff line
@@ -622,17 +622,26 @@ sub travel_action {
	if ( $params->{action} eq 'checkin' ) {

		my $status = $self->get_user_status;
		my $promise;

		if (    $status->{checked_in}
			and $status->{arr_eva}
			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->checkin_p(
		$promise->then(
			sub {
				return $self->checkin_p(
					station  => $params->{station},
					train_id => $params->{train}
				);
			}
		)->then(
			sub {
				my $destination = $params->{dest};
@@ -648,18 +657,27 @@ sub travel_action {

				# Silently ignore errors -- if they are permanent, the user will see
				# them when selecting the destination manually.
				my ( $still_checked_in, undef ) = $self->checkout(
				return $self->checkout_p(
					station => $destination,
					force   => 0
				);
			}
		)->then(
			sub {
				my ( $still_checked_in, undef ) = @_;
				if ( my $destination = $params->{dest} ) {
					my $station_link = '/s/' . $destination;
					$self->render(
						json => {
							success     => 1,
						redirect_to => $still_checked_in ? '/' : $station_link,
							redirect_to => $still_checked_in
							? '/'
							: $station_link,
						},
					);
				}
				return;
			}
		)->catch(
			sub {
				my ($error) = @_;
@@ -673,10 +691,13 @@ sub travel_action {
		)->wait;
	}
	elsif ( $params->{action} eq 'checkout' ) {
		my ( $still_checked_in, $error ) = $self->checkout(
		$self->render_later;
		$self->checkout_p(
			station => $params->{station},
			force   => $params->{force}
		);
		)->then(
			sub {
				my ( $still_checked_in, $error ) = @_;
				my $station_link = '/s/' . $params->{station};

				if ($error) {
@@ -691,10 +712,26 @@ sub travel_action {
					$self->render(
						json => {
							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' ) {
		my $status = $self->get_user_status;
@@ -747,11 +784,13 @@ sub travel_action {
		)->wait;
	}
	elsif ( $params->{action} eq 'cancelled_to' ) {
		my ( undef, $error ) = $self->checkout(
		$self->render_later;
		$self->checkout_p(
			station => $params->{station},
			force   => 1
		);

		)->then(
			sub {
				my ( undef, $error ) = @_;
				if ($error) {
					$self->render(
						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' ) {
		my $error = $self->journeys->delete(