package HomePanel::Driver;
use Moo;
use 5.10.0;
use IO::Async::Loop::EV;
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 curry::weak;
use namespace::autoclean;
has loop => ( is => 'lazy' );
sub _build_loop { IO::Async::Loop::EV->new() }
has user_agent => ( is => 'lazy' );
sub _build_user_agent {
require LWP::UserAgent;
return LWP::UserAgent->new(timeout=>20);
}
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,
$self->curry::weak::forecast_timer_cb(),
);
}
sub forecast_timer_cb {
my ($self) = @_;
$self->forecast_response(
$self->forecast->request(
$self->forecast_request
)
);
}
has bus_request => (
is => 'ro',
default => sub {
WebService::TFL::Bus::Request->new({
StopPointName => 'Hotspur Road',
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,
$self->curry::weak::bus_timer_cb(),
);
}
sub bus_timer_cb {
my ($self) = @_;
$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,
$self->curry::weak::tube_timer_cb(),
);
}
sub tube_timer_cb {
my ($self) = @_;
$self->tube_response(
$self->tube->request()
);
}
has writer_timer => ( is => 'lazy' );
sub _build_writer_timer {
my ($self) = @_;
$self->_new_timer(
5,
$self->curry::weak::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;