App-RoboBot
view release on metacpan or search on metacpan
lib/App/RoboBot/Plugin/API/Kegerator.pm view on Meta::CPAN
has 'ua' => (
is => 'rw',
isa => 'LWP::UserAgent',
default => sub {
my $ua = LWP::UserAgent->new;
$ua->agent('App::RoboBot');
$ua->timeout(5);
return $ua;
},
);
has 'last_check' => (
is => 'rw',
isa => 'DateTime',
default => sub { DateTime->now },
);
has 'beer_cache' => (
is => 'rw',
isa => 'HashRef',
default => sub { {} },
);
has 'valid_config' => (
is => 'rw',
isa => 'Bool',
traits => [qw( SetOnce )],
);
sub init {
my ($self, $bot) = @_;
# Verify we have all the necessary config keys, so we can make a much
# simpler ->valid_config check everywhere else.
if (exists $self->bot->config->plugins->{'kegerator'}{'api_host'}
&& exists $self->bot->config->plugins->{'kegerator'}{'api_path_taps'}
&& exists $self->bot->config->plugins->{'kegerator'}{'api_path_beer'}) {
$self->valid_config(1);
} else {
$self->valid_config(0);
# No need to initialize anything else related to the watcher, since we
# don't have the config keys we'll need for that.
return;
}
# Coerce notification targets into an arrayref from the configuration, in
# case only one was specified (Config::Any will have only treated it as a
# hashref, instead of an arrayref of hashrefs. Simplifies notification
# loop later on.
if (exists $self->bot->config->plugins->{'kegerator'}{'notify'}) {
$self->bot->config->plugins->{'kegerator'}{'notify'} = [
$self->bot->config->plugins->{'kegerator'}{'notify'}
] if ref($self->bot->config->plugins->{'kegerator'}{'notify'}) eq 'HASH';
# Only set the watcher if we have at least one channel to notify.
return unless @{$self->bot->config->plugins->{'kegerator'}{'notify'}} > 0;
$self->watcher(
AnyEvent->timer(
after => 30,
cb => sub { $self->_run_watcher($bot) },
)
);
}
}
sub show_ontap {
my ($self, $message, $command, $rpl, $tap_no) = @_;
if (defined $tap_no && $tap_no !~ m{^\d+$}o) {
$message->response->raise('Optional tap number must be an integer if specified.');
return;
}
return unless $self->valid_config;
my $taps = $self->make_keg_api_call($self->bot->config->plugins->{'kegerator'}{'api_path_taps'});
return unless defined $taps;
foreach my $tap (sort { $a->{'tap_id'} <=> $b->{'tap_id'} } @{$taps}) {
if (defined $tap_no) {
next unless $tap_no == $tap->{'tap_id'};
}
my $beer;
if (exists $self->beer_cache->{$tap->{'beer_id'}} && $self->beer_cache->{$tap->{'beer_id'}}{'cached_at'} >= (time() - 3600 * 2)) {
$beer = $self->beer_cache->{$tap->{'beer_id'}};
} else {
$beer = $self->make_keg_api_call($self->bot->config->plugins->{'kegerator'}{'api_path_beer'} . '/' . $tap->{'beer_id'});
next unless defined $beer;
# Trim down brewery location string for anything brewed in the US.
$beer->{'brewery_loc'} =~ s{,\s+United\s+States.*}{}igs;
$self->beer_cache->{$tap->{'beer_id'}} = $beer;
$self->beer_cache->{$tap->{'beer_id'}}{'cached_at'} = time();
}
$message->response->push(
sprintf('*Tap %d:* %s (%s) by %s, %s - %s ABV%s',
$tap->{'tap_id'},
($beer->{'beer_name'} // 'n/a'),
($beer->{'beer_style'} // 'n/a'),
($beer->{'brewery_name'} // 'n/a'),
($beer->{'brewery_loc'} // 'n/a'),
($beer->{'abv'} ? sprintf('%.1f%%', $beer->{'abv'}) : 'n/a'),
($tap->{'pct_full'} ? sprintf(', %d%% remaining', $tap->{'pct_full'} * 100) : ''),
)
);
}
return;
}
sub make_keg_api_call {
my ($self, $path, $args) = @_;
return unless $self->bot->config->plugins->{'kegerator'}{'api_host'};
my $uri = URI->new;
$uri->scheme($self->bot->config->plugins->{'kegerator'}{'api_scheme'} // 'https');
$uri->host($self->bot->config->plugins->{'kegerator'}{'api_host'});
if (ref($path) eq 'ARRAY') {
$uri->path_segments(@{$path});
} else {
$uri->path($path);
}
if (defined $args && ref($args) eq 'HASH' && scalar(keys(%{$args})) > 0) {
$uri->query_form($args);
}
my $req = HTTP::Request->new( GET => $uri->as_string );
my $response = $self->ua->request($req);
return unless $response->is_success;
my $json;
eval {
$json = decode_json($response->decoded_content);
};
return if $@;
return $json;
}
sub _run_watcher {
my ($self, $bot) = @_;
# TODO: Call base API path, get JSON
# TODO: Loop through keg list, compare each one's last_updated with the
# plugin's last_check attribute. Any with a new update should be
# added to a list of tap#->beerid
# TODO: If any tap#'s were marked as new, call the beer detail API endpoint
# to get beer name, ABV, IBU, etc.
# TODO: If any @output to send, construct a mock Response object for each
# plugin->notice[server+channel], and send notifications out.
# TODO: Update plugin's last_check timestamp.
$self->watcher(
AnyEvent->timer(
after => 30,
cb => sub { $self->_run_watcher($bot) },
)
);
}
__PACKAGE__->meta->make_immutable;
1;
( run in 1.351 second using v1.01-cache-2.11-cpan-677af5a14d3 )