diff options
Diffstat (limited to 'lib/WebService/TFL')
-rw-r--r-- | lib/WebService/TFL/Bus.pm | 41 | ||||
-rw-r--r-- | lib/WebService/TFL/Bus/Fields.pm | 77 | ||||
-rw-r--r-- | lib/WebService/TFL/Bus/Prediction.pm | 26 | ||||
-rw-r--r-- | lib/WebService/TFL/Bus/Request.pm | 38 | ||||
-rw-r--r-- | lib/WebService/TFL/Bus/Response.pm | 62 | ||||
-rw-r--r-- | lib/WebService/TFL/Bus/Response/BaseVersion.pm | 15 | ||||
-rw-r--r-- | lib/WebService/TFL/Bus/Response/FlexibleMessage.pm | 7 | ||||
-rw-r--r-- | lib/WebService/TFL/Bus/Response/Prediction.pm | 7 | ||||
-rw-r--r-- | lib/WebService/TFL/Bus/Response/Stop.pm | 7 | ||||
-rw-r--r-- | lib/WebService/TFL/Bus/Response/URAVersion.pm | 17 | ||||
-rw-r--r-- | lib/WebService/TFL/Bus/ResponseTypeRole.pm | 38 | ||||
-rw-r--r-- | lib/WebService/TFL/Bus/Types.pm | 14 | ||||
-rw-r--r-- | lib/WebService/TFL/TubeStatus.pm | 43 | ||||
-rw-r--r-- | lib/WebService/TFL/TubeStatus/Response.pm | 27 | ||||
-rw-r--r-- | lib/WebService/TFL/TubeStatus/Response/Line.pm | 25 | ||||
-rw-r--r-- | lib/WebService/TFL/TubeStatus/Response/LineStatus.pm | 24 | ||||
-rw-r--r-- | lib/WebService/TFL/TubeStatus/Types.pm | 11 |
17 files changed, 118 insertions, 361 deletions
diff --git a/lib/WebService/TFL/Bus.pm b/lib/WebService/TFL/Bus.pm index 3559755..8f43c0f 100644 --- a/lib/WebService/TFL/Bus.pm +++ b/lib/WebService/TFL/Bus.pm @@ -1,41 +1,44 @@ package WebService::TFL::Bus; use Moo; -use namespace::autoclean; use Types::URI 'Uri'; -use Type::Utils 'duck_type'; +use Types::Standard -types; +use Future::AsyncAwait; use WebService::TFL::Bus::Response; +use namespace::clean; has user_agent => ( - isa => duck_type(['get']), - is => 'lazy', - + isa => HasMethods['do_request'], + is => 'ro', + required => 1, ); -sub _build_user_agent { - require LWP::UserAgent; - my $ua = LWP::UserAgent->new(); - $ua->env_proxy; - return $ua; -} has uri => ( isa => Uri, is => 'ro', coerce => Uri->coercion, - default => 'http://countdown.api.tfl.gov.uk/interfaces/ura/instant_V1', + default => 'https://api.tfl.gov.uk/StopPoint/__/Arrivals', ); -sub request { - my ($self,$request) = @_; +has parser => ( + is => 'lazy', + builder => sub { JSON->new->utf8 }, +); + +async sub request { + my ($self,$stop_id) = @_; - my $http_response = $self->user_agent->get( - $request->request_uri($self->uri) + my $uri = $self->uri->clone; + $uri->path_segments( + map { $_ eq '__' ? $stop_id : $_ } $uri->path_segments ); + + my $http_response = await $self->user_agent->do_request(uri => $uri); + if ($http_response->is_success) { my $json = $http_response->content; - return WebService::TFL::Bus::Response->new_from_json( - $request->ReturnList, - $json + return WebService::TFL::Bus::Response->new_from_response( + $self->parser->decode($json) ); } else { diff --git a/lib/WebService/TFL/Bus/Fields.pm b/lib/WebService/TFL/Bus/Fields.pm deleted file mode 100644 index b3d555f..0000000 --- a/lib/WebService/TFL/Bus/Fields.pm +++ /dev/null @@ -1,77 +0,0 @@ -package WebService::TFL::Bus::Fields; -use strict; -use warnings; - -sub stop_return_fields { - qw( - StopPointName - StopID - StopCode1 - StopCode2 - StopPointType - Towards - Bearing - StopPointIndicator - StopPointState - Latitude - Longitude - ); -} - -sub prediction_return_fields { - stop_return_fields(), - qw( - VisitNumber - LineID - LineName - DirectionID - DestinationText - DestinationName - VehicleID - TripID - RegistrationNumber - EstimatedTime - ExpireTime - ), -} - -sub flexible_return_fields { - stop_return_fields, - qw( - MessageUUID - MessageType - MessagePriority - MessageText - StartTime - ExpireTime - ), -} - -sub query_fields { - qw( - StopAlso - Circle - StopPointName - StopID - StopCode1 - StopCode2 - StopPointType - Towards - Bearing - StopPointIndicator - StopPointState - VisitNumber - LineID - LineName - DirectionID - DestinationText - DestinationName - VehicleID - TripID - RegistrationNumber - MessageType - MessagePriority - ); -} - -1; diff --git a/lib/WebService/TFL/Bus/Prediction.pm b/lib/WebService/TFL/Bus/Prediction.pm new file mode 100644 index 0000000..670baf7 --- /dev/null +++ b/lib/WebService/TFL/Bus/Prediction.pm @@ -0,0 +1,26 @@ +package WebService::TFL::Bus::Prediction; +use Moo; +use Types::Standard -all; +use Types::DateTime -all; +use namespace::clean; + +has [qw(stationName lineName towards)] => ( + is => 'ro', + isa => Str, + required => 1, +); + +has 'expectedArrival' => ( + is => 'ro', + isa => DateTimeUTC->plus_coercions( Format['ISO8601'] ), + required => 1, + coerce => 1, +); + +sub new_from_response { + my ($class,$response_data) = @_; + + return $class->new($response_data); +} + +1; diff --git a/lib/WebService/TFL/Bus/Request.pm b/lib/WebService/TFL/Bus/Request.pm deleted file mode 100644 index dda6586..0000000 --- a/lib/WebService/TFL/Bus/Request.pm +++ /dev/null @@ -1,38 +0,0 @@ -package WebService::TFL::Bus::Request; -use Moo; -use Types::Standard -all; -use WebService::TFL::Bus::Fields; -use namespace::autoclean; - -for my $field (WebService::TFL::Bus::Fields->query_fields) { - has $field => ( - is => 'rw', - predicate => "has_$field", - ); -} - -has ReturnList => ( - is => 'rw', - isa => ArrayRef, - predicate => 'has_ReturnList', -); - -sub request_uri { - my ($self,$base_uri) = @_; - - my $uri = $base_uri->clone; - my %form; - for my $field (WebService::TFL::Bus::Fields->query_fields) { - my $pred = "has_$field"; - if ($self->$pred) { - $form{$field} = $self->$field; - } - } - if ($self->has_ReturnList) { - $form{ReturnList}=join ',',@{$self->ReturnList} - } - $uri->query_form(\%form); - return $uri; -} - -1; diff --git a/lib/WebService/TFL/Bus/Response.pm b/lib/WebService/TFL/Bus/Response.pm index e05d49d..0f811fc 100644 --- a/lib/WebService/TFL/Bus/Response.pm +++ b/lib/WebService/TFL/Bus/Response.pm @@ -1,55 +1,25 @@ package WebService::TFL::Bus::Response; use Moo; -use Class::Load 'load_class'; -use Type::Utils 'class_type'; use Types::Standard -all; -use JSON; -use namespace::autoclean; +use WebService::TFL::Bus::Prediction; +use namespace::clean; -sub line_class { - "WebService::TFL::Bus::Response::$_[0]"; -} - -my %line_map = ( - 0 => 'Stop', - 1 => 'Prediction', - 2 => 'FlexibleMessage', - 3 => 'BaseVersion', - 4 => 'URAVersion', +has predictions => ( + is => 'ro', + isa => ArrayRef[InstanceOf['WebService::TFL::Bus::Prediction']], ); -for my $field (values %line_map) { - my $class = line_class($field); - load_class($class); - has $field => ( - is => 'ro', - isa => ArrayRef[class_type { class => $class }], - ); -} - -sub new_from_json { - my ($class,$return_list,$json) = @_; - - my $parser = JSON->new->utf8; - - my %return_set;@return_set{@$return_list}=(); - unless (%return_set) { - @return_set{qw(StopPointName LineName EstimatedTime)}=(); - } - my %args; - - while ($json) { - my ($array,$consumed) = $parser->decode_prefix($json); - - my $array_type = $line_map{$array->[0]}; - my $line_class = line_class($array_type); - push @{$args{$array_type}}, - $line_class->new_from_array(\%return_set,$array); - - substr($json,0,$consumed)=''; - } - - return $class->new(\%args); +sub new_from_response { + my ($class,$response_data) = @_; + + return $class->new({ + predictions => [ + sort { $a->expectedArrival <=> $b->expectedArrival } + map { WebService::TFL::Bus::Prediction->new_from_response($_) } + grep { $_->{'$type'} =~ /\bPrediction\b/ } + $response_data->@* + ], + }); } 1; diff --git a/lib/WebService/TFL/Bus/Response/BaseVersion.pm b/lib/WebService/TFL/Bus/Response/BaseVersion.pm deleted file mode 100644 index 07edbcb..0000000 --- a/lib/WebService/TFL/Bus/Response/BaseVersion.pm +++ /dev/null @@ -1,15 +0,0 @@ -package WebService::TFL::Bus::Response::BaseVersion; -use Moo; -use namespace::autoclean; - -has Version => ( - is => 'ro', -); - -sub new_from_array { - my ($class,$return_set,$array) = @_; - - return $class->new({Version => $array->[1]}); -} - -1; diff --git a/lib/WebService/TFL/Bus/Response/FlexibleMessage.pm b/lib/WebService/TFL/Bus/Response/FlexibleMessage.pm deleted file mode 100644 index 603ef6b..0000000 --- a/lib/WebService/TFL/Bus/Response/FlexibleMessage.pm +++ /dev/null @@ -1,7 +0,0 @@ -package WebService::TFL::Bus::Response::FlexibleMessage; -use Moo; -use namespace::autoclean; -use WebService::TFL::Bus::ResponseTypeRole; -with ResponseTypeRole('flexible'); - -1; diff --git a/lib/WebService/TFL/Bus/Response/Prediction.pm b/lib/WebService/TFL/Bus/Response/Prediction.pm deleted file mode 100644 index 49a4b76..0000000 --- a/lib/WebService/TFL/Bus/Response/Prediction.pm +++ /dev/null @@ -1,7 +0,0 @@ -package WebService::TFL::Bus::Response::Prediction; -use Moo; -use namespace::autoclean; -use WebService::TFL::Bus::ResponseTypeRole; -with ResponseTypeRole('prediction'); - -1; diff --git a/lib/WebService/TFL/Bus/Response/Stop.pm b/lib/WebService/TFL/Bus/Response/Stop.pm deleted file mode 100644 index 30f2f91..0000000 --- a/lib/WebService/TFL/Bus/Response/Stop.pm +++ /dev/null @@ -1,7 +0,0 @@ -package WebService::TFL::Bus::Response::Stop; -use Moo; -use namespace::autoclean; -use WebService::TFL::Bus::ResponseTypeRole; -with ResponseTypeRole('stop'); - -1; diff --git a/lib/WebService/TFL/Bus/Response/URAVersion.pm b/lib/WebService/TFL/Bus/Response/URAVersion.pm deleted file mode 100644 index fc0b41f..0000000 --- a/lib/WebService/TFL/Bus/Response/URAVersion.pm +++ /dev/null @@ -1,17 +0,0 @@ -package WebService::TFL::Bus::Response::URAVersion; -use Moo; -use namespace::autoclean; - -for my $field (qw(Version TimeStamp)) { - has $field => ( - is => 'ro', - ); -} - -sub new_from_array { - my ($class,$return_set,$array) = @_; - - return $class->new({Version => $array->[1],TimeStamp => $array->[2]}); -} - -1; diff --git a/lib/WebService/TFL/Bus/ResponseTypeRole.pm b/lib/WebService/TFL/Bus/ResponseTypeRole.pm deleted file mode 100644 index 7f48419..0000000 --- a/lib/WebService/TFL/Bus/ResponseTypeRole.pm +++ /dev/null @@ -1,38 +0,0 @@ -package WebService::TFL::Bus::ResponseTypeRole; -use Package::Variant - importing => [ 'Moo::Role'], - subs => [ 'has' ]; -use WebService::TFL::Bus::Fields; -use WebService::TFL::Bus::Types 'DateTimeMillis'; - -sub make_variant { - my ($class,$target_package,$type) = @_; - - my $method = $type . '_return_fields'; - my @fields = WebService::TFL::Bus::Fields->$method; - - for my $field (@fields) { - has $field => ( - is => 'ro', - ( $field =~ /Time$/ ? ( - isa => DateTimeMillis, - coerce => DateTimeMillis->coercion, - ) : () ), - ); - } - - install new_from_array => sub { - my ($class,$return_set,$array) = @_; - - my %args; - my $i=1; - for my $field (@fields) { - next unless exists $return_set->{$field}; - $args{$field}=$array->[$i]; - ++$i; - } - return $class->new(\%args); - } -} - -1; diff --git a/lib/WebService/TFL/Bus/Types.pm b/lib/WebService/TFL/Bus/Types.pm deleted file mode 100644 index e67fe32..0000000 --- a/lib/WebService/TFL/Bus/Types.pm +++ /dev/null @@ -1,14 +0,0 @@ -package WebService::TFL::Bus::Types; -use Type::Library -base, -declare => 'DateTimeMillis'; -use Types::Standard -all; -use Type::Utils -all; -use Types::DateTime 'DateTimeT'; -use namespace::autoclean; - -declare DateTimeMillis, as DateTimeT; -coerce DateTimeMillis, from Num, via { - require DateTime; - DateTime->from_epoch( epoch => $_ / 1000 ) -}; - -1; diff --git a/lib/WebService/TFL/TubeStatus.pm b/lib/WebService/TFL/TubeStatus.pm index b0ba260..52d573d 100644 --- a/lib/WebService/TFL/TubeStatus.pm +++ b/lib/WebService/TFL/TubeStatus.pm @@ -1,39 +1,44 @@ package WebService::TFL::TubeStatus; use Moo; -use Type::Utils 'duck_type'; use Types::URI 'Uri'; -use XML::LibXML; -use XML::LibXML::XPathContext; +use Types::Standard -types; +use Future::AsyncAwait; use WebService::TFL::TubeStatus::Response; -use namespace::autoclean; +use namespace::clean; has user_agent => ( - isa => duck_type(['get']), - is => 'lazy', + isa => HasMethods['do_request'], + is => 'ro', + required => 1, ); -sub _build_user_agent { - require LWP::UserAgent; - my $ua = LWP::UserAgent->new(); - $ua->env_proxy; - return $ua; -} has uri => ( isa => Uri, is => 'ro', coerce => Uri->coercion, - default => 'http://cloud.tfl.gov.uk/TrackerNet/LineStatus', + default => 'https://api.tfl.gov.uk/Line/Mode/tube/Status', ); -sub request { +has parser => ( + is => 'lazy', + builder => sub { JSON->new->utf8 }, +); + +async sub request { my ($self) = @_; - my $doc = XML::LibXML->load_xml(location => $self->uri) - or die "Couldn't fetch tube status"; - my $xpath=XML::LibXML::XPathContext->new($doc); - $xpath->registerNs('ws','http://webservices.lul.co.uk/'); + my $http_response = await $self->user_agent->do_request(uri => $self->uri); + + if ($http_response->is_success) { + my $json = $http_response->content; - return WebService::TFL::TubeStatus::Response->new_from_xml($doc,$xpath); + return WebService::TFL::TubeStatus::Response->new_from_response( + $self->parser->decode($json) + ); + } + else { + die $http_response->status_line; + } } 1; diff --git a/lib/WebService/TFL/TubeStatus/Response.pm b/lib/WebService/TFL/TubeStatus/Response.pm index 191abe7..b6b104b 100644 --- a/lib/WebService/TFL/TubeStatus/Response.pm +++ b/lib/WebService/TFL/TubeStatus/Response.pm @@ -1,30 +1,25 @@ package WebService::TFL::TubeStatus::Response; use Moo; -use WebService::TFL::TubeStatus::Types -all; use WebService::TFL::TubeStatus::Response::Line; use Types::Standard -all; -use namespace::autoclean; +use namespace::clean; has lines => ( is => 'ro', - isa => ArrayRef[LineT], + isa => ArrayRef[InstanceOf['WebService::TFL::TubeStatus::Response::Line']], required => 1, ); -sub new_from_xml { - my ($class,$doc,$xpath) = @_; +sub new_from_response { + my ($class,$response_data) = @_; - my @lines; - - for my $ls ($xpath->findnodes(q{/ws:ArrayOfLineStatus/ws:LineStatus},$doc)) { - my ($line)=$xpath->findnodes(q{ws:Line},$ls); - - my $line_object = WebService::TFL::TubeStatus::Response::Line->new_from_xml($line,$ls,$xpath); - - push @lines,$line_object; - } - - return $class->new({lines=>\@lines}); + return $class->new({ + lines=> [ + map { WebService::TFL::TubeStatus::Response::Line->new_from_response($_) } + grep { $_->{'$type'} =~ /\bLine\b/ } + $response_data->@* + ], + }); } 1; diff --git a/lib/WebService/TFL/TubeStatus/Response/Line.pm b/lib/WebService/TFL/TubeStatus/Response/Line.pm index 9779443..f962418 100644 --- a/lib/WebService/TFL/TubeStatus/Response/Line.pm +++ b/lib/WebService/TFL/TubeStatus/Response/Line.pm @@ -1,13 +1,12 @@ package WebService::TFL::TubeStatus::Response::Line; use Moo; use Types::Standard -all; -use WebService::TFL::TubeStatus::Types -all; use WebService::TFL::TubeStatus::Response::LineStatus; -use namespace::autoclean; +use namespace::clean; has id => ( is => 'ro', - isa => Num, + isa => Str, required => 1, ); @@ -19,20 +18,20 @@ has name => ( has status => ( is => 'ro', - isa => LineStatusT, + isa => InstanceOf['WebService::TFL::TubeStatus::Response::LineStatus'], required => 1, ); -sub new_from_xml { - my ($class,$line,$status,$xpath) = @_; - - my %init_arg; - - $init_arg{id} = $line->findvalue(q{@ID}); - $init_arg{name} = $line->findvalue(q{@Name}); - $init_arg{status} = WebService::TFL::TubeStatus::Response::LineStatus->new_from_xml($status,$xpath); +sub new_from_response { + my ($class,$response_data) = @_; - return $class->new(\%init_arg); + return $class->new({ + id => $response_data->{id}, + name => $response_data->{name}, + status => WebService::TFL::TubeStatus::Response::LineStatus->new_from_response( + $response_data->{lineStatuses}[0], + ), + }); } 1; diff --git a/lib/WebService/TFL/TubeStatus/Response/LineStatus.pm b/lib/WebService/TFL/TubeStatus/Response/LineStatus.pm index 6caa7d6..2e8e22b 100644 --- a/lib/WebService/TFL/TubeStatus/Response/LineStatus.pm +++ b/lib/WebService/TFL/TubeStatus/Response/LineStatus.pm @@ -1,33 +1,23 @@ package WebService::TFL::TubeStatus::Response::LineStatus; use Moo; use Types::Standard -all; -use namespace::autoclean; +use namespace::clean; -has is_active => ( +has [qw(statusSeverity statusSeverityDescription)] => ( is => 'ro', - isa => Bool, + isa => Str, required => 1, ); -has [qw(code class description details)] => ( +has reason => ( is => 'ro', isa => Str, - required => 1, ); -sub new_from_xml { - my ($class,$ls,$xpath) = @_; - - my %init_arg; - - my ($status) = $xpath->findnodes(q{ws:Status},$ls); - $init_arg{code} = $status->findvalue(q{@ID}); - $init_arg{is_active} = $status->findvalue(q{@IsActive}) eq 'true'; - $init_arg{class} = $status->findvalue(q{@CssClass}); - $init_arg{description} = $status->findvalue(q{@Description}); - $init_arg{details} = $ls->findvalue(q{@StatusDetails}); +sub new_from_response { + my ($class,$response_data) = @_; - return $class->new(\%init_arg); + return $class->new($response_data); } 1; diff --git a/lib/WebService/TFL/TubeStatus/Types.pm b/lib/WebService/TFL/TubeStatus/Types.pm deleted file mode 100644 index d1cb141..0000000 --- a/lib/WebService/TFL/TubeStatus/Types.pm +++ /dev/null @@ -1,11 +0,0 @@ -package WebService::TFL::TubeStatus::Types; -use strict; -use warnings; -use Type::Library -base, -declare => qw(LineT LineStatusT); -use Type::Utils -all; -use namespace::autoclean; - -class_type LineT, { class => 'WebService::TFL::TubeStatus::Response::Line' }; -class_type LineStatusT, { class => 'WebService::TFL::TubeStatus::Response::LineStatus' }; - -1; |