view release on metacpan or search on metacpan
examples/webhook.pl view on Meta::CPAN
return app -> log -> warn('invalid secret')
unless $c -> req
-> headers
-> header('X-Telegram-Bot-Api-Secret-Token')
eq $secret;
}
$bot -> process_update($c -> req -> json);
};
$bot -> set_callbacks(message => sub {
my (undef, $update) = @_;
my $chat_id = $$update{message}{from}{id};
my $text = $$update{message}{text};
eval {
$bot -> api -> sendMessage({
chat_id => $chat_id,
text => $text eq '/start' ? 'Hey there!' : "You said: $text",
});
};
lib/Bot/Telegram.pm view on Meta::CPAN
$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(@_);
$self -> on(polling_error => DEFAULT_POLLING_ERROR_CB);
$self -> on(callback_error => DEFAULT_CALLBACK_ERROR_CB);
$self
lib/Bot/Telegram.pm view on Meta::CPAN
? $resolve
: $reject) -> ($ua, $tx);
})
});
}
################################################################################
# Callbacks
################################################################################
sub set_callbacks {
my ($self, %cbs) = @_;
while ( my ($key, $val) = each %cbs) {
$self -> callbacks -> {$key} = $val;
}
return $self;
}
sub remove_callbacks {
my ($self, @events) = @_;
foreach my $event (@events) {
delete $self -> callbacks -> {$event};
}
return $self;
}
################################################################################
# Updates
################################################################################
sub shift_offset {
lib/Bot/Telegram.pm view on Meta::CPAN
sub process_update {
my ($self, $update) = @_;
$self -> current_update($update);
my $type = $self -> _get_update_type($update);
eval {
# If update type is recognized, call the appropriate callback
if ($type) {
$self -> callbacks
-> {$type}
-> ($self, $update);
}
# Otherwise report an unknown update
else { $self -> emit(unknown_update => $update) }
};
# Report a callback error if we failed to handle the update
$self -> emit(callback_error => $update, $@) if $@;
lib/Bot/Telegram.pm view on Meta::CPAN
return $self;
}
# Return the update type if we have a callback for it
# Or just return zero, if we don't
sub _get_update_type {
my ($self, $update) = @_;
exists $$update{$_}
and return $_
for keys %{ $self -> callbacks };
return 0;
}
################################################################################
# Webhook
################################################################################
sub set_webhook {
my ($self, $config, $cb) = @_;
lib/Bot/Telegram.pm view on Meta::CPAN
#!/usr/bin/env perl
use Mojo::Base -strict;
use Bot::Telegram;
my $bot = Bot::Telegram
-> new
-> init_api(token => YOUR_TOKEN_HERE);
$bot -> set_callbacks(
message => sub {
my ($bot, $update) = @_;
my $chat = $$update{message}{chat}{id};
my $user = $$update{message}{from}{username};
my $text = $$update{message}{text};
say "> User $user says: $text";
$bot -> api -> sendMessage(
{ chat_id => $chat, text => "Hello there, $user!" },
lib/Bot/Telegram.pm view on Meta::CPAN
my ($bot, $update) = @_;
say "> No callback defined for this kind of updates. Anyway, here's the update object:";
require Data::Dump;
Data::Dump::dd($update);
});
Emitted when an update of an unregistered type is received.
The type is considered "unregistered" if there is no matching callback configured
(i.e. C<$self -E<gt> callbacks -E<gt> {$update_type}> is not a coderef).
Exists mostly for debugging purposes.
There are no default subscribers to this event.
=head1 PROPERTIES
L<Bot::Telegram> inherits all properties from L<Mojo::EventEmitter> and implements the following new ones.
=head2 api
my $api = $bot -> api;
$bot -> api($api);
L<WWW::Telegram::BotAPI> instance used by the bot. Can be initialized via the L</"init_api"> method, or set directly.
=head2 callbacks
my $callbacks = $bot -> callbacks;
$bot -> callbacks($callbacks);
Hash reference containing callbacks for different update types.
While you can manipulate it directly, L</"set_callbacks"> and L</"remove_callbacks"> methods provide a more convinient interface.
=head2 current_update
my $update = $bot -> current_update;
say "User $$update{message}{from}{username} says: $$update{message}{text}";
Update that is currently being processed.
=head2 ioloop
lib/Bot/Telegram.pm view on Meta::CPAN
=head2 process_update
$bot = $bot -> process_update($update);
Process a single update and store it in L</"current_update">.
This function will not C<die> regardless of the operation success.
Instead, the L</"callback_error"> event is emitted if things go bad.
=head2 remove_callbacks
$bot = $bot -> remove_callbacks(qw/message edited_message/);
# From now on, bot considers 'message' and 'edited_message' unknown updates
Remove callbacks for given update types, if set.
=head2 set_callbacks
$bot -> set_callbacks(
message => sub {
my ($bot, $update) = @_;
handle_message $update;
},
edited_message => sub {
my ($bot, $update) = @_;
handle_edited_message $update;
}
);
Set callbacks to match specified update types.
=head2 set_webhook
$bot = $bot -> set_webhook($config);
$bot = $bot -> set_webhook($config, $cb);
Set a webhook. All arguments will be proxied to L<WWW::Telegram::BotAPI/"api_request">.
This function ensures that actual C<setWebhook> request will not be made as long as the polling loop is active:
t/01-polling.t view on Meta::CPAN
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);
});
my $time_before = steady_time;
t/04-events.t view on Meta::CPAN
result => [ map { state $i = 0 ; update $_ => $i++ } qw/message edited_message callback_query/ ]
};
my $messages = $log -> capture('warn');
my $upd_counter = 0;
my $count_update = sub { ++ $upd_counter };
$bot
-> api(bot_api $res)
-> set_callbacks(
message => sub { die 'failed to process message' },
edited_message => $count_update,
callback_query => $count_update)
-> start_polling;
Mojo::IOLoop -> start;
is scalar @$messages, 1, 'got 1 failure as expected';
is $upd_counter, 2, 'processed 2 updates as expected';
like $$messages[0], qr/Update processing failed: failed to process message/,
t/04-events.t view on Meta::CPAN
};
};
subtest callback_error => sub {
plan tests => 2;
my $bot = Bot::Telegram -> new;
my $res = json_response { ok => \1, result => [update message => 1] };
$bot -> api(bot_api $res);
$bot -> set_callbacks(message => sub { This shit will definitely die });
my ($pass, @args) = 0;
$bot -> unsubscribe('callback_error');
$bot -> on(callback_error => sub { @args = @_ });
$bot -> start_polling;
Mojo::IOLoop -> one_tick;
$bot -> stop_polling;
subtest arguments => sub {
t/04-events.t view on Meta::CPAN
my $res = json_response {
ok => \1,
result => [
(update message => 1),
(update thing => 2),
],
};
$bot -> api(bot_api $res);
# $bot -> unsubscribe('unknown_update'); # there's nothing by default
$bot -> set_callbacks(message => sub { 0 }); # make 'message' a "known" update
my ($pass, @args) = 0;
$bot -> on(unknown_update => sub { @args = @_ });
$bot -> start_polling;
Mojo::IOLoop -> one_tick;
$bot -> stop_polling;
subtest arguments => sub {
plan tests => 2;
t/05-updates.t view on Meta::CPAN
subtest 'on/off' => sub {
plan tests => 3;
my $bot = Bot::Telegram -> new;
my $api = bot_api;
my $message = sub { 'this is a callback for message' };
my $edited_message = sub { 'this is a callback for edited_message' };
$bot -> set_callbacks(message => $message, edited_message => $edited_message);
is_deeply [ sort keys %{$bot -> callbacks} ], [qw/edited_message message/],
'set callbacks';
subtest subs => sub {
is $bot -> callbacks -> {message}, $message;
is $bot -> callbacks -> {edited_message}, $edited_message;
};
$bot -> remove_callbacks(qw/message edited_message/);
is_deeply [ keys %{$bot -> callbacks} ], [],
'remove callbacks';
};
subtest 'update types recognition' => sub {
my $upds = [];
my @list = qw/message callback_query inline_query foobar/;
my $update_id = 0;
plan tests => 4;
push @$upds, (update $_ => $update_id++) for @list;
t/05-updates.t view on Meta::CPAN
my $api = bot_api
json_response {
ok => \1,
result => $upds,
};
$bot -> api($api);
my $correctly_recognized = [];
$bot -> set_callbacks($_ => updcheck $_) for @list;
$bot -> start_polling;
Mojo::IOLoop -> one_tick;
$bot -> stop_polling;
};
done_testing;
t/06-sync.t view on Meta::CPAN
result => [map {update $_ => $update_id++} @UPDATES]
}), json_response({
ok => \1,
result => [update something => 0]
}), sub { ++ $req_counter };
$bot -> api($api) -> api -> {async} = 0;
my @processed;
# let's make ourselves a callbacks generator to simplify things a little bit
my $push = sub {
my $name = shift;
sub {
shift; # discard $bot reference
note "(callback) $name";
push @processed, $name if ref shift -> {$name} eq 'HASH'
}
};
$bot -> set_callbacks(
(map { $_ => $_ -> $push } qw/message callback_query something/),
edited_message => sub {
('edited_message' -> $push) -> (@_);
# This will disable the polling loop once the second update is processed.
# 'callback_query' will still get processed since it's already retrieved,
# but 'something' should never be reached.
$bot -> stop_polling;
}
);
$bot -> start_polling(interval => 3);
is $req_counter, 1, 'made 1 request';
is_deeply \@processed, \@UPDATES, 'processed all updates received during the first iteration';
};
subtest 'Events', sub {
my $bot = Bot::Telegram -> new;
$bot -> api(bot_api json_response { ok => \1, result => [update message => 1] });
$bot -> set_callbacks(message => sub { die 'catch me if you can' });
$bot -> api -> {async} = 0;
my $passed;
$bot -> unsubscribe('callback_error');
$bot -> on(callback_error => sub {
note 'inside the callback';
$bot -> stop_polling;
$passed = 1;
});