diff --git a/content/posts/2022/python-irc-bot.md b/content/posts/2022/python-irc-bot.md new file mode 100644 index 0000000..ee7e933 --- /dev/null +++ b/content/posts/2022/python-irc-bot.md @@ -0,0 +1,222 @@ +--- +title: "IRC бот на Python 3" +date: 2022-09-23T22:54:34+03:00 +draft: false +tags: [python, irc, tutorial] +--- + +## Введение + +Это руководство своего рода обобщение уже размешённой в сети информации, +по написанию IRC бота. + +## Протокол IRC + +Протокол IRC предназначен для обмена сообщениями в режиме реального времени. + +IRC использует протокол **TCP** и опционально криптографический **TLS**. + +В данном руководстве для общения я буду использовать библиотеку `socket` +из страндартной библиотеки Python. + +Общение с сервером осуществаляется посредством отправки команд, вот основные из них: + +### `USER` + +Команда, для приветствия с сервером. + +```text +USER : +``` + +Например: + +```text +USER iiiypuk localhost localhost :Alexander +``` + +### PASS + +Пароль, если необходимо для захода на сервер. + +### NICK + +Команда для смены ника. + +### PONG + +Ответ на команду сервера `PING`. + +### JOIN + +Команда для входа в канал. + +```text +JOIN # +``` + +### PART + +Команда, чтобы выйти из канала. + +Можно указать причину ухода из канала, добисав второй необязательный аргумет. + +```text +PART #support_chanel +``` + +### PRIVMSG + +Команда, чтобы послать сообщение пользователю или на канал. + +```text +PRIVMSG : +``` + +### QUIT + +Команда, чтобы отсоединиться от сервера. + +## Команды сервера + +Помимо команд, которые можно отправить на сервер, клиент также получает команды от сервера. + +### PING + +Сервер время от времени посылает команду PING, на случай, если клиент повиснет. + +Если быстро не ответить на команду пинг командой PONG, сервер разорвёт соединение. + +### : + +```text +:!@ +``` + +`` событие, созданное пользователем ``. + +Например `` отправил тебе сообщение или выкинул тебя из канала. + +### PRIVMSG + +```text +PRIVMSG : +``` + +Новое сообщение, личное или в канал. + +### KICK + +```text +KICK +``` + +Пользователя `` кикнули с канала ``. + +## Подключение к серверу + +Определим некоторые переменные + +```python +server = 'iiiypuk.me' # адрес сервера +channel = '#admin' # имя канала +botnick = 'porteus' # ник бота +``` + +Инициализируем socket и подключимся к серверу. + +```python +import socket + +irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +irc.connect((server, 6667)) +``` + +Для работы с сервером этого не достаточно, но необходимо. + +Следующий шаг, это "регистрация" бота на сервере. + +```python +irc.send(str.encode('USER ' + botnick + ' localhost localhost :This is a bot!\n')) +irc.send(str.encode('NICK ' + botnick + '\n')) +irc.send(str.encode('JOIN '+ channel +'\n')) +``` + +Обратил внимание на функцию `str.encode`, которая преобразует +**UTF-8** строку в набор байтов. + +Если попытаться передать обычною строку, получим ошибку `TypeError`: + +```text +Traceback (most recent call last): + File "/home/user/Temp/IRCBOT/./bot.py", line 14, in + irc.send('USER ' + botnick + ' localhost localhost :This is a bot!\n') +TypeError: a bytes-like object is required, not 'str' +``` + +Можно добавить `b` перед строкой и использовать функцию `bytes()` +для преобразования строк в набор байтов, но я лучше воспринимаею код, +когда используется метод `encode`. + +```python +irc.send(b'USER ' + bytes(botnick, encoding = 'utf-8') + b' localhost localhost :This is a bot!\n') +``` + +И в конечном итоге получаем сообщения от сервера. + +```python +while True: + text = irc.recv(2040) + print(text) +``` + +Ниже представлю полный листинг программы. + +```python +#!/usr/bin/env python3 + +import socket + +server = 'iiiypuk.me' +channel = '#admin' +botnick = 'porteus' + +irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +print('Connecting to: ' + server) + +irc.connect((server, 6667)) +irc.send(str.encode('USER ' + botnick + ' localhost localhost :This is a bot!\n')) +irc.send(str.encode('NICK ' + botnick + '\n')) +irc.send(str.encode('JOIN '+ channel +'\n')) + +while True: + text = irc.recv(2040) + print(text) + + if text.find(str.encode('PING')) != -1: + irc.send(str.encode('PONG ' + str(text.split()[1]) + '\r\n')) +``` + +Я в главный цикл программы добавил ответ за команду сервера **PING**. + +## Полезные действия + +Через инстукцию `if` добавим боту полезную функцию. +Бот будет возвращать текущее время в формате UNIX. + +```python +# !time - return current timestamp + if text.find(str.encode('!time')) != -1: + ts = time.time() + irc.send(str.encode('PRIVMSG #admin :{}\r\n'.format(int(ts)))) +``` + +Код бота можно найти по этой ссылке. +[iiiypuk/snipplets.dev:Python/irc-bot.py](https://git.a2s.su/iiiypuk/snipplets.dev/src/branch/master/~/Python/irc-bot.py) + +## Используемые материалы + +* Internet Relay Chat Protocol RFC [[Ссылка]](http://web.archive.org/web/20170929015000/http://www2.irchelp.org:80/irchelp/rfc/rfc.html) +* How do i program a simple IRC bot in python? [[Ссылка]](https://stackoverflow.com/questions/2968408/how-do-i-program-a-simple-irc-bot-in-python) +* Краткое описание протокола IRC и пример бота [[Ссылка]](https://eax.me/irc-descr/) +* Простейший IRC-бот на Python, а также при чем тут Slack, Gitter и прочие веб-чаты [[Ссылка]](https://eax.me/python-irc-bot/)