ICQ New: инструкция по разведению ботов
Каждый раз, заходя в мессенджер, мы встречаем ботов в самых различных своих проявлениях. Одни рассказывают про погоду, другие разыгрывают бургеры, а третьи так и вообще кидают мемы под настроение. Наверняка у многих из вас проскакивала мысль: «А не сделать ли мне своего бота?». К сожалению, частенько такие мысли разбиваются о непонимание, как вообще сделать бота. Наверное, для этого нужно быть крутым айтишником и разбираться в миллионах технологий? На самом деле, нет. И сегодня мы попытаемся показать, что создание своего бота — процесс простой и понятный. Разберем полный цикл создания бота, от получения необходимых данных из мессенджера до написания кода и его запуска на сервере.
Некоторое время назад в ICQ сильно обновилась платформа ботов. Она стала более дружелюбной, понятной и удобной. С помощью Python-библиотеки от разработчиков мы и будем создавать своего первого бота.
Первым делом
Для начала, нужно быть зарегистрированным в ICQ. Сделать это можно через приложение для мобильного телефона, компьютера или прямо из браузера в веб-версии.
После регистрации можно приступать к заведению собственного бота в системе:
- Найти metabot в ICQ.
- Написать ему команду /newbot .
- Отправить имя для своего нового бота (должно оканчиваться на bot ).
После этого metabot пришлет данные вашего бота:
- botId : уникальный номер бота;
- nick : имя бота для поиска;
- token : токен, который используется для сетевых запросов к серверу.
Всё, бот создан. Его можно найти в поиске, написать ему сообщение. Теперь нам нужно сделать так, чтобы бот был активным и что-то отвечал.
На страннице https://icq.com/botapi/#/ есть полное описание методов API. Они используются для взаимодействия с сервером. Разберем некоторые из них подробнее.
Базовый метод — /events/get . Он используется для получения новых событий бота. Например, если кто-то написал боту, то это событие будет отдаваться при запросе /events/get . Давайте напишем боту какое-нибудь сообщение и проверим появление соответствующего события. Сделать это можно, например, в браузере. Для этого нужно перейти по адресу https://api.icq.net/bot/v1/events/get?token=Ваш токен&pollTime=1&lastEventId=0. Параметр pollTime отвечает за длительность удержания запроса сервером. Например, если ввести значение 60, то сервер в течение 60 секунд будет ждать событий для бота, а если их не будет за это время, то сервер вернет пустой массив событий. lastEventId отвечает за последнее обработанное событие. Другими словами, события со значениями меньше, чем переданное, будут отсечены.
После перехода по этому адресу на экране появится что-то подобное:
Таким же образом можно отправить сообщение от имени бота с помощью метода /messages/sendText .
Изучать эти методы подробнее не нужно, у нас есть готовая Python-библиотека, которая позволяет, не вдаваясь в подробности, писать своего бота.
Пишем код?
Да, но для начала нам нужно подготовить для этого свой компьютер. Будем использовать Python третьей версии (скачайте версию для своей ОС здесь: https://www.python.org/downloads/ и менеджер пакетов pip здесь: https://pip.pypa.io/en/stable/installing/ ) Также, нужно установить библиотеку для работы с ботами:
$ pip3 install —upgrade mailru-im-bot
Вот теперь можно приступать.
Пишем!
В качестве примера будем писать игрового бота, который будет проверять знания простейшей математики. Работать он будет так: человек пишет боту какое-нибудь сообщение, тот представляется и предлагает поиграть. После того, как пользователь соглашается, бот генерирует простой математический пример и 4 варианта на выбор. Когда пользователь нажимает кнопку с выбранным ответом, бот отвечает, правильно или неправильно.
Итак, бот в первую очередь должен получать события от сервера. Для этого нам нужно, помимо импортирования всех библиотек, создать объект класса Bot и запустить получение обновлений:
import logging from bot . bot import Bot logging.basicConfig(format=’%(asctime)s %(levelname)s %(message)s’, datefmt=’%Y.%m.%d %I:%M:%S %p’, level=logging.DEBUG) TOKEN = «» #your token here def main(): bot = Bot (token=TOKEN) bot .start_polling() if __name__ == ‘__main__’: main()
Здесь мы импортируем библиотеку для журналирования и запускаем ее. Также импортируем библиотеку для ICQ-ботов, задаем необходимый параметр token , создаем объект класса Bot и запускаем получение обновлений от сервера ( bot .start_polling() ).
Сейчас наш бот может получать события, но не может их обрабатывать. Дополним бота, чтобы он мог отвечать на сообщения. Для этого добавим необходимые импорты:
import json from bot .handler import MessageHandler
json нужен для форматирования части сообщения, отвечающей за кнопки. MessageHandler нужен для добавления в код обработчика новых сообщений.
Далее, нам нужна функция, которая будет составлять сообщение для ответа:
def startup( bot , event): default_markup = [ [<"text": "Начать!", "callbackData": "start">] ] first_message_text = «Привет! Я — игровой бот. Начнем?» bot .send_text(chat_id=event.from_chat, text=first_message_text, inline_keyboard_markup=json.dumps(default_markup))
Она принимает на вход созданного бота и событие нового сообщения. default_markup — матрица кнопок (объект «список», состоящий из массива строк кнопок. В нашем случае это единственная кнопка Начать!). first_message_text — строка, текст которой будет отправлен пользователю. Метод send_text принимает:
- chat_id (поле из обрабатываемого события) — идентификатор чата, из которого было получено сообщение,
- текст отправляемого сообщения,
- и inline_keyboard_markup — наши кнопки.
Теперь осталось описать вызов этой функции при получении сообщения. Для этого в библиотеке есть специальная конструкция:
Она позволяет при получении нового сообщения автоматически вызывать функцию startup() с необходимыми параметрами. Этот обработчик нужно поместить в функцию main() . У нас получился вот такой код, который позволяет отправлять стартовое сообщение при получении ботом любого сообщения:
import logging import json from bot . bot import Bot from bot .handler import MessageHandler logging.basicConfig(format=’%(asctime)s %(levelname)s %(message)s’, datefmt=’%Y.%m.%d %I:%M:%S %p’, level=logging.DEBUG) TOKEN = «» #your token here def startup( bot , event): default_markup = [ [<«text»: «Начать!», «callbackData»: «start»>] ] first_message_text = «Привет! Я — игровой бот. Начнем?» bot .send_text(chat_id=event.from_chat, text=first_message_text, inline_keyboard_markup=json.dumps(default_markup)) def main(): bot = Bot (token=TOKEN) bot .dispatcher.add_handler(MessageHandler(callback=startup)) bot .start_polling() if __name__ == ‘__main__’: main()
Для пользователя это будет выглядеть так:
Рассмотрим подробнее кнопку, которую мы отправляли в сообщении:
Помимо текста, который написан на кнопке, в сообщении есть поле callbackData . При нажатии на кнопку сервер генерирует событие нажатия на кнопку. В нём он передает это поле как идентификатор нажатой кнопки. То есть, по этой строке, полученной от сервера, мы можем судить, какую именно кнопку нажал пользователь. таким образом, дальше нам нужно добавить в бота логику обработки нажатия на кнопку. Для этого нам снова потребуется импортировать необходимые методы:
from bot .handler import BotButtonCommandHandler from bot .filter import Filter
Первая строка — обработчик события нажатия на кнопку, вторая — фильтр, помогающий понять, какая именно кнопка нажата. Также нам нужно описать логику ответа на нажатия кнопки:
def start( bot , event): question = » operands = [«+», «-«, «*»] operations_count = randrange(3)+2 for i in range(operations_count): question += str(randrange(9)) question += choice(operands) question = question[:-1] answer = eval(question) buttons = [ [<'text': str(answer), 'callbackData': "right">, <'text': str(answer+1), 'callbackData': "wrong">], [<'text': str(answer-1), 'callbackData': "wrong">, <'text': str(answer+2), 'callbackData': "wrong">]] shuffle(buttons[0]) shuffle(buttons[1]) shuffle(buttons) bot .answer_callback_query( query_id=event.data[‘queryId’], text=’Новый вопрос’) bot .send_text(chat_id=event.data[‘message’][‘chat’][‘chatId’], text=question, inline_keyboard_markup=json.dumps(buttons))
По аналогии с сообщениями, функция принимает на вход такие же аргументы. Затем генерируется пример и массив кнопок с ответами. Один из ответов будет правильным. По этому признаку у ответов будут разные callbackData . В конце нужно обязательно вызвать метод answer_callback_query с параметрами:
- query_id — уникальный номер события нажатия на кнопку,
- и text — текст, который будет показан во всплывающей подсказке при нажатии на кнопку.
С помощью вызова этого метода мы покажем пользователю, что бот принял нажатие на кнопку. Иначе на кнопке какое-то время будет отображаться индикатор загрузки. Еще с помощью метода send_text нужно отправить само сообщение с вопросом и кнопками ответов.
Давайте сразу добавим и функции для обработки правильных и неправильных ответов:
def right( bot , event): bot .send_text(chat_id=event.data[‘message’][‘chat’][‘chatId’], text=’Правильно!’) start( bot , event) def wrong( bot , event): bot .send_text(chat_id=event.data[‘message’][‘chat’][‘chatId’], text=’Неправильно:(‘) start( bot , event)
Эти функции будут вызываться при нажатии на правильный и неправильный ответы. И после сообщения с правильным ответом пользователь получит новый вопрос.
Всё, осталось только добавить обработчики нажатия на кнопки:
bot .dispatcher.add_handler(BotButtonCommandHandler( callback=start, filters=Filter.callback_data(«start»))) bot .dispatcher.add_handler(BotButtonCommandHandler( callback=wrong, filters=Filter.callback_data(«wrong»))) bot .dispatcher.add_handler(BotButtonCommandHandler( callback=right, filters=Filter.callback_data(«right»)))
В каждом из этих трех обработчиков записан фильтр по callbackData (например, filters=Filter.callback_data(«start») ) и функция для вызова.
На этом программирование бота завершено. Итоговый код выглядит так:
import logging import json from bot . bot import Bot from bot .handler import BotButtonCommandHandler from bot .handler import MessageHandler from bot .filter import Filter from random import randrange, choice, random, shuffle logging.basicConfig(format=’%(asctime)s %(levelname)s %(message)s’, datefmt=’%Y.%m.%d %I:%M:%S %p’, level=logging.DEBUG) TOKEN = «» #your token here def startup( bot , event): default_markup = [ [<"text": "Начать!", "callbackData": "start">] ] first_message_text = «Привет! Я — игровой бот. Начнем?» bot .send_text(chat_id=event.from_chat, text=first_message_text, inline_keyboard_markup=json.dumps(default_markup)) def start( bot , event): question = » operands = [«+», «-«, «*»] operations_count = randrange(3)+2 for i in range(operations_count): question += str(randrange(9)) question += choice(operands) question = question[:-1] answer = eval(question) buttons = [ [<'text': str(answer), 'callbackData': "right">, <'text': str(answer+1), 'callbackData': "wrong">], [<'text': str(answer-1), 'callbackData': "wrong">, <'text': str(answer+2), 'callbackData': "wrong">]] shuffle(buttons[0]) shuffle(buttons[1]) shuffle(buttons) bot .answer_callback_query( query_id=event.data[‘queryId’], text=’Новый вопрос’) bot .send_text(chat_id=event.data[‘message’][‘chat’][‘chatId’], text=question, inline_keyboard_markup=json.dumps(buttons)) def right( bot , event): bot .send_text(chat_id=event.data[‘message’][‘chat’][‘chatId’], text=’Правильно!’) start( bot , event) def wrong( bot , event): bot .send_text(chat_id=event.data[‘message’][‘chat’][‘chatId’], text=’Неправильно:(‘) start( bot , event) def main(): bot = Bot (token=TOKEN) bot .dispatcher.add_handler(MessageHandler(callback=startup)) bot .dispatcher.add_handler(BotButtonCommandHandler( callback=start, filters=Filter.callback_data(«start»))) bot .dispatcher.add_handler(BotButtonCommandHandler( callback=wrong, filters=Filter.callback_data(«wrong»))) bot .dispatcher.add_handler(BotButtonCommandHandler( callback=right, filters=Filter.callback_data(«right»))) bot .start_polling() if __name__ == ‘__main__’: main()
Замечу, что в нем присутствуют импорты, необходимые для работы функции генерирования вопроса. Вместо этой и других функций можно написать какую-то свою логику 🙂
Где и как запускать?
Бота удобнее всего запускать на удаленном сервере. Есть множество сервисов, которые предлагают виртуальные серверы с доступами, достаточными для установки программ. Некоторые сервисы предоставляют бесплатный тестовый период. Раз уж мы Mail.ru, то и разбирать будем на примере Mail.ru Cloud Solutions. Там простой процесс регистрации, быстрый доступ к своему серверу, а также бесплатный тестовый период без привязки банковской карты и прочих трудностей.
- Регистрируем аккаунт на https://mcs.mail.ru/.
- Создаем инстанс виртуальной машины. Все настройки оставляем без изменений, их достаточно.
- Сервис предложит скачать ключ доступа. Скачиваем.
- Теперь заходим на свою виртуальную машину: ssh -i ./xxx.pem user@ip
где ./xxx.pem — путь до скачанного ключа. - После этого нам нужно установить необходимые программы и пакеты:
Здесь мы установили Python и все необходимые библиотеки для работы нашего бота.
Осталось скопировать бота на сервер и запустить его. Из папки со скриптом выполняем: scp -i ./xxx.pem ./path/to_bot.py user@ip:
- ./xxx.pem — путь до ключа;
- ./path/to_bot.py — путь до файла с ботом;
- user@ip:
— логин, адрес и путь, куда копировать бота.
После этого файл с ботом окажется в домашней директории на удаленном сервере.
Заходим обратно на сервер и запускаем: python3
Источник
ICQ баг-информер на PHP + ActiveMQ
Я являюсь разработчиком и смотрителем довольно крупной системы он-лайн бронирования одного из московских туроператоров. Поскольку к этой системе предъявляются весьма высокие требования в плане надежности и безопасности, мне приходится отслеживать все возникающие в ней ошибки, однако постоянно заходить и просматривать, нет ли новых отчетов, не очень удобно и поэтому возникла необходимость в неком средстве мгновенного оповещения, причем оно должно поддерживать возможность отправки сообщений как из веб-части, так и из десктопных приложений.
В этой статье я хочу рассказать о своем опыте написания скрипта для мгновенного оповещения о возникающих в системе ошибках посредством ICQ сообщений. В качестве промежуточного звена и накопителя репортов используется брокер сообщений ActiveMQ, я расскажу как его установить и настроить для работы с MySQL. Главная часть — это ICQ-бот, написанный на PHP, в его обязанности входит прослушивание определенного канала в брокере и пересылка сообщений на указанные номера ICQ. Также я расскажу как запустить этот PHP скрипт в качестве службы Windows.
Схема работы данной системы следующая: приложение (веб или десктопное) при возникновении ошибки формирует некое XML-сообщение, в котором содержится краткое описание ошибки и ICQ-номер получателя. Это сообщение отправляется по STOMP протоколу брокеру ActiveMQ и попадает в очередь. На другом конце света или на той же машине находится ICQ-бот, который слушает эту очередь и при попадании в нее сообщения тут же пересылает его по указанному адресу. А теперь в деталях.
Установка и настройка ActiveMQ
Все программы будут ставиться под Windows. Пару слов о самом ActiceMQ, он представляет собой брокер сообщений, в котором есть 2 основных понятия: очереди (Queue) и темы (Topic).
Topic предназначен для оповещения большого числа подписчиков о каком-нибудь событии, например новость или выход очередного патча.
Queue представляет собой очередь заданий, на нее может быть подписано несколько слушателей, но любое сообщение получит только один из подписчиков, это как раз нам подходит.
Для начала качаем дистрибутив. Установка сводится к распаковке архива в какую-нибудь далекую папку. Для удобства работы установим его как службу Windows, для этого необходимо запустить скрипт ActiveMQ\bin\win32\InstallService.bat, наличие установленной JAVA машины предполагается само собой.
Проверить работоспособность можно через «Администрирование» -> «Службы», но только подождите секунд 10 после запуска и обновите список, на Win 2003 server у меня возникла проблема: служба вроде запускалась, но сразу же падала, долгое копание в логах и гуглах привело к простому решению – необходимо создать папку work в каталоге ActiveMQ\bin\win32.
Для настройки ActiveMQ необходимо открыть файл \conf\activemq.xml
Описываем наш брокер:
xmlns = «activemq.apache.org/schema/core» brokerName = «localhost» dataDirectory = «$
/data» destroyApplicationContextOnStop = «true» persistent = «true» useShutdownHook = «false» >
id = «mysql-ds» class = «org.apache.commons.dbcp.BasicDataSource» destroy-method = «close» >
name = «driverClassName» value = «com.mysql.jdbc.Driver»/>
name = «url» value = «jdbc:mysql://localhost/activemq?relaxAutoCommit=true»/>
name = «username» value = «activemq»/>
name = «password» value = «activemq»/>
name = «poolPreparedStatements» value = «true»/>
Блок должен располагаться за пределами тега . После перезапуска службы в БД должны будут создаться 3 таблицы, если так и произошло, значит все сделано правильно.
Идем дальше по конфигу, настроим возможные подключения:
Здесь я задал 2 различных подключения по разным протоколам, это связано с тем, что на PHP для подключения я использую библиотеку STOMP, а под Delphi удалось найти компонент стабильно работающий по TCP.
Далее займемся авторизацией, в блок добавим следующий кусок:
admins=system,sslclient,client,broker1,broker2
users=icq
guests=guest
Еще понадобится файл login.config, его проще скачать целиком и кинуть в папку /conf. После всех настроек перезапускаем службу и заходим на адрес http://localhost:8161/admin/, если все сделали правильно, вас встретит панель управления, если так, то заходим в Queues и там создаем очередь с названием icq.
Скрипт ICQ-бота
За основу бота я взял библиотеку WebIcqPro, она довольно простая и стабильная. Также понадобится библиотека для отправки сообщений брокеру, я нашел вполне стабильное решение на STOMP-протоколе, однако при разрыве соединения его вышибало, поэтому мне пришлось его немного модифицировать, чтобы появилась возможность реконнекта. Приводить весь код бота я здесь не буду, кому это действительно интересно могут скачать архив.
Для проверки работоспособности запустим бота через командную строку:
«C:\Program Files\PHP\php» C:\icqbot\icq.php
Если с настройками все в порядке, он должен установить соединение с ActiveMQ и сервером ICQ, после чего начать прослушивать канал «* Waiting for messages. ». Для отправки пробного сообщения можно воспользоваться скриптом send.php из архива:
$c = new StompConnection ( «localhost» ) ;
$result = $c -> connect ( «icq» , «bot» ) ;
Проверка русского message
$mess = iconv ( ‘cp1251’ , ‘UTF-8’ , $mess ) ;
$c -> send ( «/queue/icq» , $mess , array ( ‘persistent’ => ‘true’ ) ) ;
Мне довольно долго пришлось возится с кодировками, чтобы можно было отправлять сообщения с русским текстом, поэтому не удивляйтесь когда в скриптах увидите каскадные преобразования в различные кодировки, по другому это все работать не хотело. После вызова send.php на указанный UIN придет сообщение и в логах этот факт также отразится.
Запускаем бота как службу Windows
Для этого нам понадобится набор Windows NT Resource Kit, у кого нет качаем. Допустим все файлы бота у нас лежат в папке C:\icqbot. Открываем консоль и пишем
“C:\Program Files\Windows Resource Kits\Instsrv.exe” ICQBot “C:\Program Files\Windows Resource Kits\Srvany.exe”
Далее запускаем regedit и идем в раздел HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ICQBot внутри него создаем раздел Parameters и в нем параметр Application типа REG_SZ со значением «C:\Program Files\PHP\php.exe» C:\icqbot\icq.php
Далее идем в службы и запускаем оттуда нашего бота, теперь он полностью автономен.
Ловец ошибок для сайта
ini_set ( ‘display_errors’ , 0 ) ;
function send_report ( $message , $to = ‘1212312’ , $from = ‘SENDER’ ) <
global $send_report , $stomp_server , $stomp_url , $stomp_user , $stomp_psw ;
if ( ! $send_report ) return false ;
$c = new StompConnection ( $stomp_server ) ;
$result = $c -> connect ( $stomp_user , $stomp_psw ) ;
if ( ! is_array ( $to ) ) $to = array ( $to ) ;
foreach ( $to as $i ) <
$c -> send ( $stomp_url , iconv ( ‘cp1251’ , ‘UTF-8’ , $mess ) , array ( ‘persistent’ => ‘true’ ) ) ;
function user_log ( $errno , $errmsg , $file , $line ) <
$filename = strftime ( ‘%d.%m.%Y %H-%M-%S_’ ) . $_REQUEST [ ‘PHPSESSID’ ] . ‘.err’ ;
$fl = fopen ( ‘errors/’ . $filename , ‘w’ ) ;
$_SESSION [ ‘ERROR_TEXT’ ] = ‘WARNING: ‘ . $errmsg . ‘ in ‘ . $file . ‘ on line ‘ . $line ;
$_SESSION [ ‘ERROR_TIME’ ] = strftime ( ‘%d.%m.%Y %H-%M-%S’ ) ;
$_SESSION [ ‘ERROR_PHPSESSID’ ] = $_REQUEST [ ‘PHPSESSID’ ] ;
$_SESSION [ ‘ERROR_TYPE’ ] = ‘PHP SCRIPT ERROR’ ;
fwrite ( $fl , serialize ( $_SESSION ) ) ;
if ( $send_report ) send_report ( $_SESSION [ ‘ERROR_TEXT’ ] ) ;
По понятным причинным все содержимое этих отчетов я криптую, что и всем советую делать.
Таким образом, получилась довольно стабильная, простая и универсальная схема оповещения, позволяющая отправлять сообщения на ICQ из любого приложения на любом языке, если для него описан один из протоколов взаимодействия с ActiveMQ.
Источник