Краткое вступление
Мой первый опыт общения с помощью Всемирной сети Интернет - электронная почта. Конечно же, почта будет жить всегда, но потом появились другие потребности - к примеру общение голосом, возможность увидеть есть ли онлайн тот или иной контакт, удобство общения (особенно для мобильных телефонов).
Так позже Я познакомился с ICQ (I seek you, аська). Этот сервис уже существовал относительно долго, мне удалось даже попользоваться мобильным клиентом QIP, который работал на многих телефонах (до эры смартфонов), которые позволяли устанавливать скачанные джава приложения (очень популярная была тогда линейка телефонов Sony Ericsson). В то время (примерно 2005) тарифы на мобильный Интернет были довольно высоки, да и мобильная связь тоже не была очень дешевой. Мобильный QIP потреблял очень мало трафика и позволял связываться с людьми по всему миру, в чём определённо была выгода.
Прошло ещё немножко времени - и компьютер уже почти в каждом доме, смартфон уже почти у каждого человека. Skype быстро набирал популярность, в то время как аська теряла. Конечно, множество людей также регистрировалось в разных социальных сетях и предпочитало общение там же. Но со skype можно было делать даже видеозвонки почти в любую точку мира, а Интернет уже был быстрым и дешевым. Но вот случилася беда - Microsoft выкупила Skype. Правда, он и чуть раньше начал портиться - старые смартфоны больше его не поддерживали, а новым, но с маленькими ресурсами - skype был уже не под силу. Кроме того, некоторые люди очень беспокоились тем, что skype "прослушивается" (многие также говорят, что им скрывать нечего, но довольно неприятно осознавать сам факт прослушки). Странички в соцсетях и без всяких специальных средств как на ладони, а если ещё и "попросят", то можно расковырять всё о владельце аккаунта. И вот немалоизвестный создатель одной из таких соцсетей - Павел Дуров (кстати, довольно интересная история его выезда из родной страны, обязательно почитайте) создаёт новый месенджер - Telegram.
Telegram
Вышел этот мессенджер в 2013 году, казалось бы чем он мог соревноваться с уже существующими мессенджерами. Но, пройдя на страничку Telegram, можно увидеть, что он предлагает следующие преимущества:
- бесплатный навсегда, без реклам, без взносов;
- супер защищенный; говорят, что не дадут доступа к перепискам даже на запросы разных спецслужб;
- легковесный, работает на любой популярной платформе, а также просто в браузере;
- клиент с открытым кодом (сервер - нет).
Ну и поскольку он привязан к телефонному номеру, то автоматически импортирует конакты всех людей из вашей телефонной книги, которые уже зарегистрированы в Telegram.
А в 2015 году появились ещё и программируемые боты для Telegram. Суть в том, что Вы можете отсылать вашему боту команду как обычное сообщение (каждый созданный вами бот будет висеть в списке контактов), а ваша программа может парсить эту команду, выполнить её и прислать вам ответ в тот же чат с ботом (или прислать файл, или ничего не присылать, а просто что-то выполнить). Это очень удобно, если Вам, к примеру, надо следить за "здоровьем" какого-то вашего сервера с любой точки планеты.
Telegram Bot
Рассмотрим как это работает на простом примере. Будем писать бота, который читает и копирует файлы в директорию Dropbox. Код, который Вы здесь увидите, не идеален, но может послужить Вам стартовой площадкой.
Все запросы к API телеграм бота делаются через HTTPS протокол и имеют такой формат:
Например:
Ваш бот-токен сгенерируется при создании бота - обязательно сохраните его и никому не показывайте, хотя можно в любой момент сгенерировать новый.
Ответ на любой запрос приходит в виде красивого JSON. Если отправить боту сообщение "Hello World", а потом проверить получил ли бот что-то новенькое, то это всё будет выглядеть примерно так:
Итак, наша задача - распарсить этот JSON и послать соответствующий ему ответ (или не послать, если нет соответствия).
Для отправки ответа нужно использовать метод "sendMessage", где обязательные парамеры это сам текст сообщения и идентификатор чата - куда послать (с консоли надо "ескейпить" символ "&"):
Для написания бота Я использовал мой любимый ЯП - Python. Естественно, принимать и отправлять сообщения будем не через curl, а через высокоуровневые библиотеки Python'a (urllib, urllib2).
Этот пример можете использовать как угодно, можете даже присылать свои варианты реализации, идеи новых ботов.
Telegram
Вышел этот мессенджер в 2013 году, казалось бы чем он мог соревноваться с уже существующими мессенджерами. Но, пройдя на страничку Telegram, можно увидеть, что он предлагает следующие преимущества:
- бесплатный навсегда, без реклам, без взносов;
- супер защищенный; говорят, что не дадут доступа к перепискам даже на запросы разных спецслужб;
- легковесный, работает на любой популярной платформе, а также просто в браузере;
- клиент с открытым кодом (сервер - нет).
Ну и поскольку он привязан к телефонному номеру, то автоматически импортирует конакты всех людей из вашей телефонной книги, которые уже зарегистрированы в Telegram.
А в 2015 году появились ещё и программируемые боты для Telegram. Суть в том, что Вы можете отсылать вашему боту команду как обычное сообщение (каждый созданный вами бот будет висеть в списке контактов), а ваша программа может парсить эту команду, выполнить её и прислать вам ответ в тот же чат с ботом (или прислать файл, или ничего не присылать, а просто что-то выполнить). Это очень удобно, если Вам, к примеру, надо следить за "здоровьем" какого-то вашего сервера с любой точки планеты.
Telegram Bot
Рассмотрим как это работает на простом примере. Будем писать бота, который читает и копирует файлы в директорию Dropbox. Код, который Вы здесь увидите, не идеален, но может послужить Вам стартовой площадкой.
Все запросы к API телеграм бота делаются через HTTPS протокол и имеют такой формат:
https://api.telegram.org/bot<token>/<method>
Например:
https://api.telegram.org/bot123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11/getMe
Ваш бот-токен сгенерируется при создании бота - обязательно сохраните его и никому не показывайте, хотя можно в любой момент сгенерировать новый.
Ответ на любой запрос приходит в виде красивого JSON. Если отправить боту сообщение "Hello World", а потом проверить получил ли бот что-то новенькое, то это всё будет выглядеть примерно так:
$ curl https://api.telegram.org/bot$TOKEN/getUpdates
{"ok":true,"result":[{"update_id":373347763,
"message":{"message_id":121,"from":{"id":119435478,"first_name":"Sergius","last_name":"Master"},"chat":{"id":119435478,"first_name":"Sergius","last_name":"Master","type":"private"},"date":1447629425,"text":"Hello World"}}]}
Итак, наша задача - распарсить этот JSON и послать соответствующий ему ответ (или не послать, если нет соответствия).
Для отправки ответа нужно использовать метод "sendMessage", где обязательные парамеры это сам текст сообщения и идентификатор чата - куда послать (с консоли надо "ескейпить" символ "&"):
$ curl https://api.telegram.org/bot$TOKEN/sendMessage?text=hello+from+bot\&chat_id=119435478
#!/usr/bin/env python import json import logging import logging.handlers import os import re import shutil import signal import urllib import urllib2 from contextlib import closing from glob import glob from string import Template from time import sleep HTTP_API_TEMPLATE = Template("https://api.telegram.org/bot${TOKEN}/${METHOD}") API_TOKEN = "!!!!! HERE MUST BE YOUR API TOKEN !!!!!" class TelegramBot(object): should_continue = False def __init__(self): self.last_update_id = None self._log = logging.getLogger('file_reader') self._log.setLevel(logging.INFO) handler = logging.handlers.SysLogHandler(address = '/dev/log') log_format = "%(filename)s: %(levelname)s: %(message)s" fmt = logging.Formatter(log_format) handler.setFormatter(fmt) self._log.addHandler(handler) def get_last_message(self): if self.last_update_id: response = self.get_updates("?offset=%s" % (self.last_update_id + 1)) else: response = self.get_updates() resp_dict = json.loads(response) if resp_dict.get("result", []): last_msg_dict = resp_dict["result"][-1] self.last_update_id = int(last_msg_dict.get("update_id", 0)) return { "from": last_msg_dict["message"]["chat"]["id"], "cmd": last_msg_dict["message"]["text"] } def get_updates(self, options=""): subs_dict = {'TOKEN': API_TOKEN, 'METHOD': 'getUpdates%s' % options} get_message_url = HTTP_API_TEMPLATE.substitute(subs_dict) response = "" with closing(urllib2.urlopen(get_message_url)) as get_upd: response = get_upd.read() return response def send_response(self, text, send_to): options = "?" + urllib.urlencode({'chat_id': send_to, 'text': text}) subs_dict = {'TOKEN': API_TOKEN, 'METHOD': 'sendMessage%s' % options} send_message_url = HTTP_API_TEMPLATE.substitute(subs_dict) response = "" print send_message_url with closing(urllib2.urlopen(send_message_url)) as send_msg: response = send_msg.read() def parse_command(self, command): command = command.split() if len(command) == 1: cmd, args = command[0], "" elif len(command) == 2: cmd, args = command else: return None, None match = re.search("/\w+", cmd.strip()) if match: cmd = match.group() if re.match("^\S*$", args.strip()): return cmd, args.strip() return None, None def execute_command(self, command): """ Available commands: /help - shows this documentation /ls <directory>* - shows directory listing type /ls <directory>*.txt to show all txt files in directory /cat <file> - shows file /head <file> - shows first 10 lines of file /tail <file> - shows last 10 lines of file /cpd <file> - copy file to Dropbox/bot """ cmd, args = self.parse_command(command) if cmd == "/help": return self.execute_command.__doc__ if cmd == "/ls": return "\n".join(glob(args)) if cmd == "/cat": try: output = "" with open(args) as f: output = f.read() return output except IOError as e: return str(e) if cmd == "/head": try: output = "" with open(args) as f: output = "".join(f.readlines()[:10]) return output except IOError as e: return str(e) if cmd == "/tail": try: output = "" with open(args) as f: output = "".join(f.readlines()[-10:]) return output except IOError as e: return str(e) if cmd == "/cpd": DropboxFolder = "/home/sergius/Dropbox/bot" destination = "%s/%s" % (DropboxFolder, os.path.basename(args)) try: shutil.copyfile(args, destination) return "Copied file successfully" except Exception as e: return str(e) def check_updates_for_command(self): msg = None try: msg = self.get_last_message() except Exception as e: self._log.error("Network Error: %s " % str(e)) sleep(10) return None if msg: # Easter Egg --- if msg["cmd"].lower() == "good job": response = "Thank you, Master" # --- else: response = self.execute_command(msg["cmd"]) if response: self.send_response(response, msg["from"]) def doit(self): self._log.info('Starting telegram bot "file_reader"') TelegramBot.should_continue = True while TelegramBot.should_continue: self.check_updates_for_command() sleep(1) self._log.info('Stopping telegram bot "file_reader"') @staticmethod def signal_handler(signum, frame): TelegramBot.should_continue = False signal.signal(signal.SIGTERM, TelegramBot.signal_handler) def main(): bot = TelegramBot() bot.doit() if __name__ == "__main__": main()