PageRenderTime 111ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/RER/DataSource/Transilien.pm

https://bitbucket.org/xtab/rer-web
Perl | 152 lines | 107 code | 41 blank | 4 comment | 22 complexity | ad56d89b69323c5a62cd254f1d87b987 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. #!/usr/bin/env perl
  2. package RER::DataSource::Transilien;
  3. use RER::Gare;
  4. use RER::Gares;
  5. use RER::Train;
  6. use HTTP::Request;
  7. use LWP::UserAgent;
  8. use XML::Simple;
  9. use strict;
  10. use warnings;
  11. use utf8;
  12. use 5.010;
  13. sub do_request {
  14. my ($self, $path) = @_;
  15. my $req = HTTP::Request->new(GET => $self->{url} . $path);
  16. $req->header('User-Agent' => 'RER::Web (+http://bitbucket.org/xtab/rer-web)');
  17. $req->header('Accept' => 'application/vnd.sncf.transilien.od.depart+xml;vers=1');
  18. $req->authorization_basic($self->username, $self->password);
  19. my $ua = LWP::UserAgent->new;
  20. $ua->timeout(10);
  21. push(@LWP::Protocol::http::EXTRA_SOCK_OPTS, SendTE => 0);
  22. my $response = $ua->request($req);
  23. for ($response->code) {
  24. if ($_ == 401) { die "Authentication failed or missing (invalid API key?)\n"; }
  25. elsif ($_ == 403) {
  26. if (defined $response->header('Retry-After')) {
  27. my $retry_after = $response->header('Retry-After');
  28. die "API call quota exceeded (retry after $retry_after s)\n";
  29. }
  30. else {
  31. die "Forbidden (invalid station or other error)\n";
  32. }
  33. }
  34. elsif ($_ == 404) { die "Invalid path supplied to API call\n"; }
  35. elsif ($_ == 406) { die "Unsupported version\n"; }
  36. elsif ($_ == 500) { die "API is broken\n"; }
  37. elsif ($_ == 503) { die "API is overloaded\n"; }
  38. }
  39. return $response->decoded_content;
  40. }
  41. sub process_xml_trains {
  42. my ($self, $xml) = @_;
  43. my $xs = XML::Simple->new();
  44. my $data = $xs->XMLin($xml);
  45. my @trains;
  46. # S'il n'y a qu'un seul train, XML::Simple renvoie un hash au lieu d'un
  47. # tableau. Forcer un tableau à un seul élément dans ce cas.
  48. my @train_data = (ref $data->{train} eq 'ARRAY') ? @{$data->{train}} :
  49. (ref $data->{train} eq 'HASH') ? ( $data->{train} ) : ();
  50. foreach my $train_hash (@train_data) {
  51. my $time_type = ($train_hash->{date}{mode} eq 'R') ? 'real_time' : 'due_time';
  52. $train_hash->{date}{content} =~ m#^([\d]{2})/([\d]{2})/([\d]{4}) ([\d]{2}):([\d]{2})$#;
  53. my $time_value = DateTime->new(
  54. year => $3,
  55. month => $2,
  56. day => $1,
  57. hour => $4,
  58. minute => $5,
  59. second => 0,
  60. time_zone => 'Europe/Paris'
  61. );
  62. my $terminus;
  63. if (exists $train_hash->{term}) {
  64. $terminus = RER::Gares::find(uic => $train_hash->{term});
  65. $terminus ||= RER::Gare->new(
  66. uic => $train_hash->{term},
  67. code => '',
  68. name => "Gare " . $train_hash->{term});
  69. }
  70. else {
  71. $terminus = RER::Gare->new(
  72. uic => 0,
  73. code => '',
  74. name => "Gare non référencée");
  75. }
  76. my $train_etat = 'N';
  77. $train_etat = $train_hash->{etat} if exists $train_hash->{etat};
  78. $train_etat = 'S' if $train_etat eq 'Supprimé';
  79. $train_etat = 'R' if $train_etat eq 'Retardé'; # not sure if this works
  80. push @trains, RER::Train->new(
  81. number => $train_hash->{num},
  82. code => $train_hash->{miss},
  83. $time_type => $time_value,
  84. status => $train_etat,
  85. terminus => $terminus,
  86. );
  87. }
  88. return \@trains;
  89. }
  90. sub get_next_trains {
  91. my ($self, $station) = @_;
  92. die "Invalid station\n" if ! defined ($station);
  93. my $path = '/gare/' . $station->uic8() . '/depart/';
  94. my $data = $self->do_request($path);
  95. return $self->process_xml_trains($data);
  96. }
  97. sub url { $_[0]->{url} = $_[1] || $_[0]->{url}; }
  98. sub username { $_[0]->{username} = $_[1] || $_[0]->{username}; }
  99. sub password { $_[0]->{password} = $_[1] || $_[0]->{password}; }
  100. sub new {
  101. my ($self, %args) = @_;
  102. $self = {};
  103. return undef if ! exists $args{username};
  104. return undef if ! exists $args{password};
  105. $self->{url} = $args{url} || 'http://api.transilien.com';
  106. $self->{username} = $args{username};
  107. $self->{password} = $args{password};
  108. return bless $self, __PACKAGE__;
  109. }
  110. 1;
  111. # vi:ts=4:sw=4:et: