Merge branch 'Balduro-boteventhandler'

This commit is contained in:
Jannes Höke 2015-12-01 18:08:38 +01:00
commit 23507202e8
5 changed files with 100 additions and 34 deletions

View file

@ -9,6 +9,7 @@ Contributors
The following wonderful people contributed directly or indirectly to this project: The following wonderful people contributed directly or indirectly to this project:
- `Avanatiker <https://github.com/Avanatiker>`_ - `Avanatiker <https://github.com/Avanatiker>`_
- `Balduro <https://github.com/Balduro>`_
- `bimmlerd <https://github.com/bimmlerd>`_ - `bimmlerd <https://github.com/bimmlerd>`_
- `ErgoZ Riftbit Vaper <https://github.com/ergoz>`_ - `ErgoZ Riftbit Vaper <https://github.com/ergoz>`_
- `franciscod <https://github.com/franciscod>`_ - `franciscod <https://github.com/franciscod>`_

View file

@ -54,11 +54,13 @@ Table of contents
1. `API`_ 1. `API`_
2. `Logging`_ 2. `The Updater class`_
3. `Logging`_
3. `Examples`_ 4. `Examples`_
4. `Documentation`_ 5. `Documentation`_
- `License`_ - `License`_
@ -152,10 +154,72 @@ _`Getting started`
View the last release API documentation at: https://core.telegram.org/bots/api View the last release API documentation at: https://core.telegram.org/bots/api
------
_`The Updater class`
------
The ``Updater`` class is the new way to create bots with ``python-telegram-bot``. It provides an easy-to-use interface to the ``telegram.Bot`` by caring about getting new updates from telegram and forwarding them to the ``Dispatcher`` class. We can register handler functions in the ``Dispatcher`` to make our bot react to Telegram commands, messages and even arbitrary updates.
As with the old method, we'll need an Access Token. To generate an Access Token, we have to talk to `BotFather <https://telegram.me/botfather>`_ and follow a few simple steps (described `here <https://core.telegram.org/bots#botfather>`_).
First, we create an ``Updater`` object::
>>> from telegram import Updater
>>> updater = Updater(token='token')
For quicker access to the ``Dispatcher`` used by our ``Updater``, we can introduce it locally::
>>> dispatcher = updater.dispatcher
Now, we need to define a function that should process a specific type of update::
>>> def start(bot, update):
... bot.sendMessage(chat_id=update.message.chat_id, text="I'm a bot, please talk to me!")
We want this function to be called on a Telegram message that contains the ``/start`` command, so we need to register it in the dispatcher::
>>> dispatcher.addTelegramCommandHandler('start', start)
The last step is to tell the ``Updater`` to start working::
>>> updater.start_polling()
Our bot is now up and running (go ahead and try it)! It's not doing anything yet, besides answering to the ``/start`` command. Let's add another handler function and register it::
>>> def echo(bot, update):
... bot.sendMessage(chat_id=update.message.chat_id, text=update.message.text)
...
>>> dispatcher.addTelegramMessageHandler(echo)
Our bot should now reply to all messages that are not a command with a message that has the same content.
People might try to send commands to the bot that it doesn't understand, so we should get that covered as well::
>>> def unknown(bot, update):
... bot.sendMessage(chat_id=update.message.chat_id, text="Sorry, I didn't understand that command.")
...
>>> dispatcher.addUnknownTelegramCommandHandler(unknown)
Let's add some functionality to our bot. We want to add the ``/caps`` command, that will take some text as parameter and return it in all caps. We can get the arguments that were passed to the command in the handler function simply by adding it to the parameter list::
>>> def caps(bot, update, args):
... text_caps = ' '.join(args).upper()
... bot.sendMessage(chat_id=update.message.chat_id, text=text_caps)
...
>>> dispatcher.addTelegramCommandHandler('caps', caps)
Now it's time to stop the bot::
>>> updater.stop()
Check out more examples in the `examples folder <https://github.com/leandrotoledo/python-telegram-bot/tree/master/examples>`_!
------ ------
_`API` _`API`
------ ------
Note: Using the ``Bot`` class directly is the 'old' method, but some of this is still important information, even if you're using the ``Updater`` class!
The API is exposed via the ``telegram.Bot`` class. The API is exposed via the ``telegram.Bot`` class.
To generate an Access Token you have to talk to `BotFather <https://telegram.me/botfather>`_ and follow a few simple steps (described `here <https://core.telegram.org/bots#botfather>`_). To generate an Access Token you have to talk to `BotFather <https://telegram.me/botfather>`_ and follow a few simple steps (described `here <https://core.telegram.org/bots#botfather>`_).

View file

@ -106,7 +106,8 @@ def unknown_cli_command(bot, update):
def main(): def main():
# Create the EventHandler and pass it your bot's token. # Create the EventHandler and pass it your bot's token.
updater = Updater("TOKEN", workers=2) token = 'token'
updater = Updater(token, workers=2)
# Get the dispatcher to register handlers # Get the dispatcher to register handlers
dp = updater.dispatcher dp = updater.dispatcher
@ -125,13 +126,23 @@ def main():
# Start the Bot and store the update Queue, so we can insert updates # Start the Bot and store the update Queue, so we can insert updates
update_queue = updater.start_polling(poll_interval=0.1, timeout=20) update_queue = updater.start_polling(poll_interval=0.1, timeout=20)
''' '''
# Alternatively, run with webhook: # Alternatively, run with webhook:
update_queue = updater.start_webhook('example.com', updater.bot.setWebhook(webhook_url='https://example.com/%s' % token,
certificate=open('cert.pem', 'wb'))
update_queue = updater.start_webhook('0.0.0.0',
443, 443,
'cert.pem', url_path=token,
'key.key', cert='cert.pem',
listen='0.0.0.0') key='key.key')
# Or, if SSL is handled by a reverse proxy, the webhook URL is already set
# and the reverse proxy is configured to deliver directly to port 6000:
update_queue = updater.start_webhook('0.0.0.0',
6000)
''' '''
# Start CLI-Loop # Start CLI-Loop

View file

@ -11,7 +11,6 @@ from threading import Thread
from time import sleep from time import sleep
import subprocess import subprocess
from signal import signal, SIGINT, SIGTERM, SIGABRT from signal import signal, SIGINT, SIGTERM, SIGABRT
from telegram import (Bot, TelegramError, dispatcher, Dispatcher, from telegram import (Bot, TelegramError, dispatcher, Dispatcher,
NullHandler) NullHandler)
from telegram.utils.webhookhandler import (WebhookServer, WebhookHandler) from telegram.utils.webhookhandler import (WebhookServer, WebhookHandler)
@ -92,17 +91,23 @@ class Updater:
# Return the update queue so the main thread can insert updates # Return the update queue so the main thread can insert updates
return self.update_queue return self.update_queue
def start_webhook(self, host, port, listen='0.0.0.0', cert=None, key=None): def start_webhook(self,
listen='127.0.0.1',
port=80,
url_path='',
cert=None,
key=None):
""" """
Starts a small http server to listen for updates via webhook. If cert Starts a small http server to listen for updates via webhook. If cert
and key are not provided, the webhook will be started directly on and key are not provided, the webhook will be started directly on
http://host:port/, so SSL can be handled by another application. Else, http://listen:port/url_path, so SSL can be handled by another
the webhook will be started on https://host:port/<bot_token> application. Else, the webhook will be started on
https://listen:port/url_path
Args: Args:
host (str): Hostname or IP of the bot
port (int): Port the bot should be listening on
listen (Optional[str]): IP-Address to listen on listen (Optional[str]): IP-Address to listen on
port (Optional[int]): Port the bot should be listening on
url_path (Optional[str]): Path inside url
cert (Optional[str]): Path to the SSL certificate file cert (Optional[str]): Path to the SSL certificate file
key (Optional[str]): Path to the SSL key file key (Optional[str]): Path to the SSL key file
@ -115,7 +120,7 @@ class Updater:
name="dispatcher") name="dispatcher")
event_handler_thread = Thread(target=self._start_webhook, event_handler_thread = Thread(target=self._start_webhook,
name="updater", name="updater",
args=(host, port, listen, cert, key)) args=(listen, port, url_path, cert, key))
self.running = True self.running = True
@ -170,24 +175,10 @@ class Updater:
self.logger.info('Updater thread stopped') self.logger.info('Updater thread stopped')
def _start_webhook(self, host, port, listen, cert, key): def _start_webhook(self, listen, port, url_path, cert, key):
self.logger.info('Updater thread started') self.logger.info('Updater thread started')
use_ssl = cert is not None and key is not None use_ssl = cert is not None and key is not None
url_path = "/%s" % url_path
url_base = "https://%s:%d" % (host, port)
if use_ssl:
url_path = "/%s" % self.bot.token
certfile = open(cert, 'rb')
else:
url_path = "/"
certfile = None
# Remove webhook
self.bot.setWebhook(webhook_url=None)
# Set webhook
self.bot.setWebhook(webhook_url=url_base + url_path,
certificate=certfile)
# Create and start server # Create and start server
self.httpd = WebhookServer((listen, port), WebhookHandler, self.httpd = WebhookServer((listen, port), WebhookHandler,

View file

@ -350,7 +350,7 @@ class UpdaterTest(BaseTest, unittest.TestCase):
# Select random port for travis # Select random port for travis
port = randrange(1024, 49152) port = randrange(1024, 49152)
self.updater.start_webhook('127.0.0.1', port, self.updater.start_webhook('127.0.0.1', port,
listen='127.0.0.1', url_path='TOKEN',
cert='./tests/test_updater.py', cert='./tests/test_updater.py',
key='./tests/test_updater.py') key='./tests/test_updater.py')
sleep(0.5) sleep(0.5)
@ -411,8 +411,7 @@ class UpdaterTest(BaseTest, unittest.TestCase):
# Select random port for travis # Select random port for travis
port = randrange(1024, 49152) port = randrange(1024, 49152)
self.updater.start_webhook('127.0.0.1', port, self.updater.start_webhook('127.0.0.1', port)
listen='127.0.0.1',)
sleep(0.5) sleep(0.5)
# Now, we send an update to the server via urlopen # Now, we send an update to the server via urlopen