package HomePanel::Driver; use Moo; use 5.10.0; use IO::Async::Loop; use IO::Async::Timer::Periodic; use HomePanel::AsyncUA; use WebService::ForecastIo; use WebService::TFL::Bus; use WebService::TFL::Bus::Request; use WebService::TFL::TubeStatus; use HomePanel::Render; use Types::Path::Tiny qw(AbsFile AbsPath); use Try::Tiny; use namespace::autoclean; has loop => ( is => 'lazy' ); sub _build_loop { IO::Async::Loop->new() } has user_agent => ( is => 'lazy' ); sub _build_user_agent { HomePanel::AsyncUA->new({loop=>$_[0]->loop}); } has forecast_request => ( is => 'ro', default => sub { +{ latitude => 51.54, longitude => -0.37, exclude => ['flags','sources'], }; }, ); has forecast_response => ( is => 'rw' ); has forecast_key => ( is => 'ro', required => 1, ); has forecast => ( is => 'lazy' ); sub _build_forecast { my ($self) = @_; WebService::ForecastIo->new({ api_key => $self->forecast_key, user_agent => $self->user_agent, }); } has forecast_timer => ( is => 'lazy' ); sub _build_forecast_timer { my ($self) = @_; $self->_new_timer( 900, sub { $self->forecast_response( $self->forecast->request( $self->forecast_request ) ); }, ); } has bus_request => ( is => 'ro', default => sub { WebService::TFL::Bus::Request->new({ StopPointName => 'Hotspur Road', #Towards => 'Islip Manor', ReturnList => [qw(StopID StopCode1 VisitNumber TripID VehicleID LineID LineName DirectionID DestinationText DestinationName EstimatedTime)], }); }, ); has bus_response => ( is => 'rw' ); has bus => ( is => 'lazy', ); sub _build_bus { WebService::TFL::Bus->new({ user_agent => $_[0]->user_agent, }); } has bus_timer => ( is => 'lazy' ); sub _build_bus_timer { my ($self) = @_; $self->_new_timer( 30, sub { $self->bus_response( $self->bus->request( $self->bus_request ) ); }, ); } has tube => ( is => 'lazy', ); sub _build_tube { WebService::TFL::TubeStatus->new({ user_agent => $_[0]->user_agent, }); } has tube_response => ( is => 'rw' ); has tube_timer => ( is => 'lazy' ); sub _build_tube_timer { my ($self) = @_; $self->_new_timer( 300, sub { $self->tube_response( $self->tube->request() ); }, ); } has writer_timer => ( is => 'lazy' ); sub _build_writer_timer { my ($self) = @_; $self->_new_timer( 5, sub { $self->write_page }, ); } sub _new_timer { my ($self,$interval,$code) = @_; my $timer = IO::Async::Timer::Periodic->new( interval => $interval, first_interval => 0, on_tick => sub { try { $code->(); } catch { warn "Problem: $_; ignoring" } }, reschedule => 'drift', ); $self->loop->add($timer); return $timer; } has template_file => ( is => 'ro', isa => AbsFile, coerce => AbsFile->coercion, required => 1, ); has output_file => ( is => 'ro', isa => AbsPath, coerce => AbsPath->coercion, required => 1, ); sub write_page { my ($self) = @_; my $output = HomePanel::Render->new({ template_file => $self->template_file, forecast => $self->forecast_response, bus => $self->bus_response, tube => $self->tube_response, })->render; $self->output_file->spew_utf8($output); } sub start { my ($self) = @_; $self->forecast_timer->start; $self->bus_timer->start; $self->tube_timer->start; $self->writer_timer->start; } 1;