NAME

Bot::ChatBots::Telegram::WebHook - Telegram updates receiver, web hook

SYNOPSIS

use Log::Any qw< $log >;
use Log::Any::Adapter;
use Mojolicious::Lite;
Log::Any::Adapter->set('Stderr');
plugin 'Bot::ChatBots::Telegram' => instances => [
   [
      'WebHook',
      processor  => \&processor,
      register   => 1,
      token      => $ENV{TOKEN},
      unregister => 0,
      url        => 'https://example.com:8443/mybot',
   ],
   # more can follow here...
];
app->start;
sub processor { # tube-compliant
   my $record = shift; # ... $record is normalized, by default

   # ... your business logic goes here...
   my $message = 'Howdy!';

   # In a WebHook you're actually processing a HTTP Request from
   # Telegram, so you can set a response via Mojolicious
   if (automatic_via_https_response()) { # WebHook only
      $record->{response} = $message;
   }
   elsif (do_it_yourself_via_https_response()) { # WebHook only
      $record->{source}{refs}{controller}->render(text => $message);
      $record->{source}{flags}{rendered} = 1; # if Bot::ChatBot <= 0.006
   }
   elsif (automatic_via_sender()) { # same as LongPoll
      $record->{send_response} = $message;
   }
   elsif (do_it_yourself_via_sender()) { # same as LongPoll
      my $sender = $record->{source}{refs}{sender};
      $sender->send_response($message, record => $record);
   }
   # else nothing is sent back, just a HTTP 204 by default

   return $record; # follow on..
}

DESCRIPTION

This is an updates receiver and dispatcher for the Telegram infrastructure. It connects to Telegram's API for webhooks style (i.e. waiting for push messages to arrive), so you need a routable address/port to get the ball rolling.

Strictly speaking, you MUST only provide a "processor" and either "url" or "path". The latter is used to set a POST route, while the former is what is called whenever a new message arrives through that route.

Most probably you will also want to automatically register your webhook at Telegram. In this case, you MUST also provide a "token". You can also set automatic registration (and unregistration) when creating the object.

When invoked, the "processor" tube can set a response through either of the following keys:

response

send the response as the HTTP Response to the HTTP Request that determined the Update. This is only available for WebHooks (LongPoll does not receive HTTP requests because it... polls), and has the further characteristic of not receiving a response itself (because it's already a response). Note that this parameter is ignored if you generate the HTTP response yourself (via the standard Mojolicious way of doing this);

send_response

send the response using "sender". In this it behaves exactly as the Bot::ChatBots::Telegram::LongPoll correspondent.

You can also set both of them: they are independent mechanisms and as long as you understand how they work there is no reason why you shouldn't. The following diagram will hopefully help you with this.

.                            ..Bot Application.....
                             :                    :
  __________________         :     ____________   :
 /                  \        :    /            \  :
 |                  |-1---------->|            |  :
 |  Telegram Server |        :    |  WebHook   |  :
 |                  |<----------2-|            |  :
 \__________________/   "response"\____________/  :
             |  ^            :        |           :
             5  |            :        3 "send_response"
             |  |            :        |           :
             |  |            :     ___v______     :
             |  |            :    /          \    :
             |  +---------------4-|          |    :
             |               :    |  Sender  |    :
             +------------------->|          |    :
                             :    \__________/    :
                             :                    :
                             :....................:

  1, 2: WebHook Request/Response
  3   : internal call
  4, 5: Telegram API Request/Response

ACCESSORS

This class consumes the following roles, inheriting their accessors:

and also adds its own, as described in the sections below. It is worth noticing the presence of "sender" in Bot::ChatBots::Telegram::Role::Source, which gives you back a Bot::ChatBots::Telegram::Sender object suitable for sending messages to the Telegram API; the same object is used internally to send responses to Update requests when send_response is specified.

auto_register

my $boolean = $obj->auto_register;

get the value of the automatic registration flag, which can be set upon construction via option register. When set, the "register" method will be called automatically upon construction.

NOTE: this parameters is initialized via the register option in the constructor "new".

auto_unregister

my $boolean = $obj->auto_unregister;

get the value of the automatic unregistration flag, which can be set upon construction via option unregister. When set, the "unregister" method will be called automatically upon destruction.

Note that some PaaS environment (notably Dokku) might keep the "old" instance around while the new one is already up and running. In this case, it is suggested to keep this boolean value to its default false value and avoid unwanted unregistrations.

NOTE: this parameters is initialized via the unregister option in the constructor "new".

certificate

$obj->certificate($certificate);
my $current = $obj->certificate;

set/get the currently installed certificate.

It can be either a string or a hash with the key certificate pointing to that string, see WWW::Telegram::BotAPI for additional details, or Telegram's documentation.

METHODS

This class consumes the following roles, inheriting their methods:

The following sections describe the addiitonal ones.

BUILD

This method is called upon object construction. It takes care to call "install_route" from Bot::ChatBots::Role::WebHook so that you don't have to. Additionally, if "auto_register" is true, "register" is called automatically.

DEMOLISH

This method is called upon object destruction. It takes care to call "unregister" if "auto_unregister" is set to a true value.

new

my $obj = Bot::ChatBots::Telegram::WebHook->new(%args);

# mostly used in Mojolicious applications
plugin 'Bot::ChatBots::Telegram' => instances => [ [ 'WebHook', %args ] ];

Create a new instance. Mostly used behind the scenes by Bot::ChatBots::MojoPlugin as in the second example above.

The arguments hash %hash supports the following keys:

***

all keys from Bot::ChatBots::Telegram::Role::Source and Bot::ChatBots::Role::WebHook

certificate

in case a privately generated certificate has to be used, it can be set here or passed to the "register" method. You don't need to set this if your certificate is publicly available and trusted (i.e. released by a recognised Certification Authority).

register

if true, "register" is called upon construction, without parameters.

unregister

if true, "unregister" is called upon destruction. Beware of setting this automation though, especially if your bot is installed through a platform as a service like Dokku, because this might interphere with your upgrade process.

parse_request

my @updates = $obj->parse_request($req);

Parse the request and extract updates from it. The current Telegram WebHook API sends one single update per message. Returns the update.

process

my $outcome = $obj->process($record);

Process a record. The main workhorse is inherited from Bot::ChatBots::Role::WebHook, although this wraps around it to add automatic sending of a response in case:

  • $outcome is a hash reference with a response key inside, AND

  • $record->{source}{flags}{rendered} is false (i.e. the response hasn't been rendered yet). See "process_updates" in Bot::ChatBots::Role::WebHook for more information about these flags.

When a response is rendered, $record->{source}{flags}{rendered} is set to 1 (a true value) to signal that rendering already happened (this should prevent the calling function from doing the rendering again).

register

$obj->register(%args);
$obj->register(\%args);

Register the url (possibly derived from path if needed) as the webhook in Telegram. Note that both url and path are inherited methods; you can override them in %args. Same goes for token.

If you plan to use an auto-generated certificate, you will need to provide it either setting "certificate" (possibly upon construction in "new") or via a parameter in %args.

Supported keys in %args, all overriding values in the object when applicable:

app

application object (defaults to value from inherited method app)

certificate

certificate in case it is auto-generated, defaults to value from object (see "certificate" and "new").

controller

controller object (defaults to value from inherited method app)

path

path value or object (defaults to value from inherited method app). Used in case parameter url below is not present or possibly derived from the object's url method;

token

token value (defaults to value from inherited method app)

url

webhook target URL value or object (defaults to value from inherited method app)

token

See "token" in Bot::ChatBots::Telegram::Base.

unregister

$obj->unregister;

De-register webhook from Telegram (after which you can restart using long-polling, for example).

SEE ALSO

Bot::ChatBots, Bot::ChatBots::Role::WebHook.

AUTHOR

Flavio Poletti <polettix@cpan.org>

COPYRIGHT AND LICENSE

Copyright (C) 2016, 2018 by Flavio Poletti <polettix@cpan.org>

This module is free software. You can redistribute it and/or modify it under the terms of the Artistic License 2.0.

This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose.