From d6552eb4c66265fc73e8fac8b58af00bcbeb6f71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Conde=20G=C3=B3mez?= Date: Tue, 6 Oct 2015 12:06:23 +0200 Subject: [PATCH] Add webhook examples --- examples/webhook_examples/README.md | 36 +++++++ .../webhook_cherrypy_echo_bot.py | 85 ++++++++++++++++ .../webhook_cpython_echo_bot.py | 99 +++++++++++++++++++ .../webhook_flask_echo_bot.py | 84 ++++++++++++++++ 4 files changed, 304 insertions(+) create mode 100644 examples/webhook_examples/README.md create mode 100644 examples/webhook_examples/webhook_cherrypy_echo_bot.py create mode 100644 examples/webhook_examples/webhook_cpython_echo_bot.py create mode 100644 examples/webhook_examples/webhook_flask_echo_bot.py diff --git a/examples/webhook_examples/README.md b/examples/webhook_examples/README.md new file mode 100644 index 0000000..2d47346 --- /dev/null +++ b/examples/webhook_examples/README.md @@ -0,0 +1,36 @@ +# Webhook examples using pyTelegramBotAPI + +There are 3 examples in this directory using different libraries: + +* **Python (CPython):** *webhook_cpython_echo_bot.py* + * **Pros:** + * Official python libraries, it works out of the box (doesn't require to + install anything). + * Works with Python 2 and Python 3 (need to be converted with 2to3). + * **Cons:** + * Ugly code. + * Many things to handle yourself, this can lead to errors. + * Not powerful, do the trick but the performance is low. + +* **CherryPy (3.8.0):** *webhook_cherrypy_echo_bot.py* + * **Pros:** + * It's a web application framework, cleaner code, uses objects for defining + the web application. + * Very good performance. + * The project seems to be active, latest version is recent. + * Works with Python 2 and Python 3. + * **Cons:** + * Some things are not very intuitive, reading the doc is a must. + +* **Flask (0.10.1):** *webhook_flask_echo_bot.py* + * **Pros:** + * It's a web application framework, cleaner code, uses decorator which can + be nice. + * Good performance. + * It's intuitive if you know how web application works. + * **Cons:** + * The project seems not to be very active, latest version dates 2013. + * They don't recommend to use it with Python 3, but may work. + * May be a oversized for just handling webhook petitions. + +*Latest update of this document: 2015-10-06* diff --git a/examples/webhook_examples/webhook_cherrypy_echo_bot.py b/examples/webhook_examples/webhook_cherrypy_echo_bot.py new file mode 100644 index 0000000..8faac61 --- /dev/null +++ b/examples/webhook_examples/webhook_cherrypy_echo_bot.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# This is a simple echo bot using decorators and webhook with CherryPy +# It echoes any incoming text messages and does not use the polling method. + +import cherrypy +import telebot +import logging + + +API_TOKEN = '' + +WEBHOOK_HOST = '' +WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open') +WEBHOOK_LISTEN = '0.0.0.0' # In some VPS you may need to put here the IP addr + +WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate +WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key + +# Quick'n'dirty SSL certificate generation: +# +# openssl genrsa -out webhook_pkey.pem 2048 +# openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem +# +# When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply +# with the same value in you put in WEBHOOK_HOST + +WEBHOOK_URL_BASE = "https://%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT) +WEBHOOK_URL_PATH = "/%s/" % (API_TOKEN) + + +logger = telebot.logger +telebot.logger.setLevel(logging.INFO) + +bot = telebot.TeleBot(API_TOKEN) + + +# WebhookServer, process webhook calls +class WebhookServer(object): + @cherrypy.expose + def index(self): + if 'content-length' in cherrypy.request.headers and \ + 'content-type' in cherrypy.request.headers and \ + cherrypy.request.headers['content-type'] == 'application/json': + length = int(cherrypy.request.headers['content-length']) + json_string = cherrypy.request.body.read(length) + update = telebot.types.Update.de_json(json_string) + bot.process_new_messages([update.message]) + return '' + else: + raise cherrypy.HTTPError(403) + + +# Handle '/start' and '/help' +@bot.message_handler(commands=['help', 'start']) +def send_welcome(message): + bot.reply_to(message, + ("Hi there, I am EchoBot.\n" + "I am here to echo your kind words back to you.")) + + +# Handle all other messages +@bot.message_handler(func=lambda message: True, content_types=['text']) +def echo_message(message): + bot.reply_to(message, message.text) + + +# Remove webhook, it fails sometimes the set if there is a previous webhook +bot.remove_webhook() + +# Set webhook +bot.set_webhook(url=WEBHOOK_URL_BASE+WEBHOOK_URL_PATH, + certificate=open(WEBHOOK_SSL_CERT, 'r')) + +# Start cherrypy server +cherrypy.config.update({ + 'server.socket_host': WEBHOOK_LISTEN, + 'server.socket_port': WEBHOOK_PORT, + 'server.ssl_module': 'builtin', + 'server.ssl_certificate': WEBHOOK_SSL_CERT, + 'server.ssl_private_key': WEBHOOK_SSL_PRIV +}) + +cherrypy.quickstart(WebhookServer(), WEBHOOK_URL_PATH, {'/': {}}) diff --git a/examples/webhook_examples/webhook_cpython_echo_bot.py b/examples/webhook_examples/webhook_cpython_echo_bot.py new file mode 100644 index 0000000..5c1dfc9 --- /dev/null +++ b/examples/webhook_examples/webhook_cpython_echo_bot.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# This is a simple echo bot using decorators and webhook with BaseHTTPServer +# It echoes any incoming text messages and does not use the polling method. + +import BaseHTTPServer +import ssl +import telebot +import logging + + +API_TOKEN = '' + +WEBHOOK_HOST = '' +WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open') +WEBHOOK_LISTEN = '0.0.0.0' # In some VPS you may need to put here the IP addr + +WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate +WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key + +# Quick'n'dirty SSL certificate generation: +# +# openssl genrsa -out webhook_pkey.pem 2048 +# openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem +# +# When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply +# with the same value in you put in WEBHOOK_HOST + +WEBHOOK_URL_BASE = "https://%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT) +WEBHOOK_URL_PATH = "/%s/" % (API_TOKEN) + + +logger = telebot.logger +telebot.logger.setLevel(logging.INFO) + +bot = telebot.TeleBot(API_TOKEN) + + +# WebhookHandler, process webhook calls +class WebhookHandler(BaseHTTPServer.BaseHTTPRequestHandler): + server_version = "WebhookHandler/1.0" + + def do_HEAD(self): + self.send_response(200) + self.end_headers() + + def do_GET(self): + self.send_response(200) + self.end_headers() + + def do_POST(self): + if self.path == WEBHOOK_URL_PATH and \ + 'content-type' in self.headers and \ + 'content-length' in self.headers and \ + self.headers['content-type'] == 'application/json': + json_string = self.rfile.read(int(self.headers['content-length'])) + + self.send_response(200) + self.end_headers() + + update = telebot.types.Update.de_json(json_string) + bot.process_new_messages([update.message]) + else: + self.send_error(403) + self.end_headers() + + +# Handle '/start' and '/help' +@bot.message_handler(commands=['help', 'start']) +def send_welcome(message): + bot.reply_to(message, + ("Hi there, I am EchoBot.\n" + "I am here to echo your kind words back to you.")) + + +# Handle all other messages +@bot.message_handler(func=lambda message: True, content_types=['text']) +def echo_message(message): + bot.reply_to(message, message.text) + + +# Remove webhook, it fails sometimes the set if there is a previous webhook +bot.remove_webhook() + +# Set webhook +bot.set_webhook(url=WEBHOOK_URL_BASE+WEBHOOK_URL_PATH, + certificate=open(WEBHOOK_SSL_CERT, 'r')) + +# Start server +httpd = BaseHTTPServer.HTTPServer((WEBHOOK_LISTEN, WEBHOOK_PORT), + WebhookHandler) + +httpd.socket = ssl.wrap_socket(httpd.socket, + certfile=WEBHOOK_SSL_CERT, + keyfile=WEBHOOK_SSL_PRIV, + server_side=True) + +httpd.serve_forever() diff --git a/examples/webhook_examples/webhook_flask_echo_bot.py b/examples/webhook_examples/webhook_flask_echo_bot.py new file mode 100644 index 0000000..a20fcc0 --- /dev/null +++ b/examples/webhook_examples/webhook_flask_echo_bot.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# This is a simple echo bot using decorators and webhook with flask +# It echoes any incoming text messages and does not use the polling method. + +import flask +import telebot +import logging + + +API_TOKEN = '' + +WEBHOOK_HOST = '' +WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open') +WEBHOOK_LISTEN = '0.0.0.0' # In some VPS you may need to put here the IP addr + +WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate +WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key + +# Quick'n'dirty SSL certificate generation: +# +# openssl genrsa -out webhook_pkey.pem 2048 +# openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem +# +# When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply +# with the same value in you put in WEBHOOK_HOST + +WEBHOOK_URL_BASE = "https://%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT) +WEBHOOK_URL_PATH = "/%s/" % (API_TOKEN) + + +logger = telebot.logger +telebot.logger.setLevel(logging.INFO) + +bot = telebot.TeleBot(API_TOKEN) + +app = flask.Flask(__name__) + + +# Empty webserver index, return nothing, just http 200 +@app.route('/', methods=['GET', 'HEAD']) +def index(): + return '' + + +# Process webhook calls +@app.route(WEBHOOK_URL_PATH, methods=['POST']) +def webhook(): + if flask.request.headers.get('content-type') == 'application/json': + json_string = flask.request.get_data() + update = telebot.types.Update.de_json(json_string) + bot.process_new_messages([update.message]) + return '' + else: + flask.abort(403) + + +# Handle '/start' and '/help' +@bot.message_handler(commands=['help', 'start']) +def send_welcome(message): + bot.reply_to(message, + ("Hi there, I am EchoBot.\n" + "I am here to echo your kind words back to you.")) + + +# Handle all other messages +@bot.message_handler(func=lambda message: True, content_types=['text']) +def echo_message(message): + bot.reply_to(message, message.text) + + +# Remove webhook, it fails sometimes the set if there is a previous webhook +bot.remove_webhook() + +# Set webhook +bot.set_webhook(url=WEBHOOK_URL_BASE+WEBHOOK_URL_PATH, + certificate=open(WEBHOOK_SSL_CERT, 'r')) + +# Start flask server +app.run(host=WEBHOOK_LISTEN, + port=WEBHOOK_PORT, + ssl_context=(WEBHOOK_SSL_CERT, WEBHOOK_SSL_PRIV), + debug=True)