Bot-Telegram
view release on metacpan or search on metacpan
lib/Bot/Telegram.pm view on Meta::CPAN
$self -> log -> warn("Polling failed (error type: $type): $message");
};
use constant DEFAULT_CALLBACK_ERROR_CB => sub {
my ($self, undef, $err) = @_;
$self -> log -> warn("Update processing failed: $err");
};
has [qw/api current_update polling_config/];
has [qw/_polling
_polling_timer
_polling_interval
_polling_request_id/
];
has callbacks => sub { {} };
has ioloop => sub { Mojo::IOLoop -> new };
has log => sub { Mojo::Log -> new -> level('info') };
sub new {
my $self = shift -> SUPER::new(@_);
lib/Bot/Telegram.pm view on Meta::CPAN
return $self unless $self -> is_polling;
for (my $agent = $self -> api -> agent) {
$self -> _polling(undef);
# In synchronous mode, it's enough to simply clear state
return $self -> _polling_interval(undef)
unless $agent -> isa('Mojo::UserAgent')
and $self -> is_async;
# In asynchronous mode, we also need to cancel existing timers
for (my $loop = Mojo::IOLoop -> singleton) {
$loop -> remove($self -> _polling_request_id);
$loop -> remove($self -> _polling_timer)
if $self -> _polling_timer; # if another request is scheduled, cancel it
}
# Reset state
$self -> _polling_request_id(undef)
-> _polling_interval(undef)
-> _polling_timer(undef);
}
$self
}
sub is_polling { !! shift -> _polling }
# In asynchronous mode: process getUpdates response or handle errors, if any
# In synchronous mode, WWW::Telegram::BotAPI::parse_error takes care of error handling for us.
sub _process_getUpdates_results {
lib/Bot/Telegram.pm view on Meta::CPAN
$self -> process_update($_)
-> shift_offset
for @$result;
}
}
return unless $self -> is_polling;
$self -> log -> trace('still polling, scheduling another iteration...');
if ($async) {
my $tid = Mojo::IOLoop -> timer(
$retry_after // $self -> _polling_interval,
sub { $self -> tap(sub { $self -> log -> trace("it's polling time!") })
-> _poll });
$self -> _polling_timer($tid);
} else {
my $d = $retry_after // $self -> _polling_interval;
# Sleep
$self -> ioloop -> timer($d, sub { $self -> ioloop -> stop });
$self -> ioloop -> start;
$self -> log -> trace("it's polling time!");
$self -> _poll;
}
}
sub _poll {
my $self = shift;
lib/Bot/Telegram.pm view on Meta::CPAN
{ timeout => 20, offset => 0 }
=item restart
Set to true if the loop is already running, otherwise an exception will be thrown.
=item interval
Interval in seconds between polling requests.
Floating point values are accepted (timers are set using L<Mojo::IOLoop/"timer">).
Default value is 0.3 (300ms).
=back
=head3 Exceptions
=over 4
=item C<Bot::Telegram::X::InvalidStateError>
t/01-polling.t view on Meta::CPAN
$bot = $bot = Bot::Telegram -> new -> api($api);
my $messages = $bot -> log -> capture('info');
my $polling_interval_after_rate_limit;
my $stop = sub {
$bot -> stop_polling;
Mojo::IOLoop -> stop;
};
my $t = Mojo::IOLoop -> timer(3, $stop);
$bot -> set_callbacks(message => sub {
return unless pop -> {update_id} == 2;
$polling_interval_after_rate_limit = $bot -> _polling_interval;
$stop -> ();
Mojo::IOLoop -> remove($t);
});
t/01-polling.t view on Meta::CPAN
$bot -> start_polling(interval => 0.1);
Mojo::IOLoop -> start;
my $time_after = steady_time;
note explain \@$messages;
my ($message) = grep { /Rate limit exceeded/ } @$messages;
like $message, qr/Rate limit exceeded, waiting 1s before polling again/, 'rate limit log message exists';
is $polling_interval_after_rate_limit, 0.1, 'polling interval was not affected by the rate limit timer';
note "time_before: $time_before, time_after: $time_after";
ok $time_after - $time_before >= 1, 'was on standby for (roughly) one second';
};
# config persistence
$bot = Bot::Telegram -> new -> api(bot_api random_valid_polling_response);
$bot -> start_polling;
my $config = $bot -> polling_config;
t/02-webhook.t view on Meta::CPAN
eval { $bot -> set_webhook };
is ref($@), 'Bot::Telegram::X::InvalidArgumentsError', 'error type';
is $@ -> message, 'No config provided', 'error message';
};
eval { $bot -> set_webhook({ url => 'http://localhost/' }) };
ok !$@, 'set w/o callback';
$bot -> set_webhook(sub { $set_f = 1 });
timer { ok $set_f, 'set w/callback' } 0.25;
Mojo::IOLoop -> start;
done_testing;
t/lib/Bot/Telegram/Test.pm view on Meta::CPAN
use Test::MockObject::Extends;
use Mojo::JSON qw/encode_json decode_json/;
use Mojo::UserAgent;
use Mojo::Transaction::HTTP;
use WWW::Telegram::BotAPI;
use base 'Exporter';
our @EXPORT = qw {
timer
update
loop_for_a_second
random_valid_polling_response
json_response
bot_api
};
my @UPDATES = qw/message edited_message edited_channel_post callback_query/;
sub timer(&$) { Mojo::IOLoop -> timer(pop, pop) } ## no critic
sub loop_for_a_second {
timer { Mojo::IOLoop -> stop } 1;
Mojo::IOLoop -> start;
}
sub update {
my ($type, $id) = @_;
return {
$type => {
foo => 'bar',
baz => 'qux',
t/lib/Bot/Telegram/Test.pm view on Meta::CPAN
$hook -> ($method, $postdata)
if ref $hook eq 'CODE';
my $tx = Mojo::Transaction::HTTP -> new;
$tx -> res($res);
$tx -> res($res);
return $self -> {async}
? timer { return $cb -> ($self -> {agent}, $tx) if ref $cb eq 'CODE' } 0.1
: _handle_error_sync $tx;
}
);
return $api;
}
1
__END__
=encoding utf8
=head1 DESCRIPTION
General-purpose testing functions
=head1 FUNCTIONS
=head2 timer
timer { say 'Tick' } 1;
Registers a timer for the Mojo::IOLoop global singleton. Takes a coderef to execute and a delay (in seconds) before execution.
=head2 loop_for_a_second
loop_for_a_second;
Run Mojo::IOLoop just for one second, then shut it back down.
=head2 json_response
my $res = json_response { ok => \1, message => 'dummy' };
t/lib/Bot/Telegram/Test.pm view on Meta::CPAN
$fake_api -> setWebhook({...}, sub {
my ($ua, $tx) = @_;
say $tx -> res -> json -> {url}; # says: https://foo.bar/webhook
});
It is possible to pass multiple fake responses, in which case a new response will be shift()ed
from the responses array every time for subsequent requests to the fake api.
Once the fake responses pool is depleted, no more timers will be scheduled when you call C<api_request>.
my $fake_api = bot_api $res1, $res2;
$fake_api -> api_request('doStuff', {...}, sub ($ua, $tx) {
is_deeply $tx -> res, $res1; # okay
});
$fake_api -> api_request('doMoreStuff', {...}, sub ($ua, $tx) {
is_deeply $tx -> res, $res2; # okay
});
( run in 0.633 second using v1.01-cache-2.11-cpan-49f99fa48dc )