🗣️ IRC бот на Python 3
Введение
Это руководство своего рода обобщение уже размешённой в сети информации, по написанию IRC бота.
Протокол IRC
Протокол IRC предназначен для обмена сообщениями в режиме реального времени.
IRC использует протокол TCP и опционально криптографический TLS.
В данном руководстве для общения я буду использовать библиотеку socket
из страндартной библиотеки Python.
Общение с сервером осуществаляется посредством отправки команд, вот основные из них:
USER
Команда, для приветствия с сервером.
USER <username> <hostname> <servername> :<realname>
Например:
USER iiiypuk localhost localhost :Alexander
PASS
Пароль, если необходимо для захода на сервер.
NICK
Команда для смены ника.
PONG
Ответ на команду сервера PING
.
JOIN
Команда для входа в канал.
JOIN #<chanel_name>
PART
Команда, чтобы выйти из канала.
Можно указать причину ухода из канала, добисав второй необязательный аргумет.
PART #support_chanel
PRIVMSG
Команда, чтобы послать сообщение пользователю или на канал.
PRIVMSG <user_name> :<message>
QUIT
Команда, чтобы отсоединиться от сервера.
Команды сервера
Помимо команд, которые можно отправить на сервер, клиент также получает команды от сервера.
PING
Сервер время от времени посылает команду PING, на случай, если клиент повиснет.
Если быстро не ответить на команду пинг командой PONG, сервер разорвёт соединение.
:
:<nickname>!<username>@<hostname> <event>
<event>
событие, созданное пользователем <nickname>
.
Например <nickname>
отправил тебе сообщение или выкинул тебя из канала.
PRIVMSG
PRIVMSG <receiver> :<message>
Новое сообщение, личное или в канал.
KICK
KICK <chanel> <nickname>
Пользователя <nickname>
кикнули с канала <chanel>
.
Подключение к серверу
Определим некоторые переменные
server = 'iiiypuk.me' # адрес сервера
channel = '#admin' # имя канала
botnick = 'porteus' # ник бота
Инициализируем socket и подключимся к серверу.
import socket
irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
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'))
Обратил внимание на функцию str.encode
, которая преобразует
UTF-8 строку в набор байтов.
Если попытаться передать обычною строку, получим ошибку TypeError
:
Traceback (most recent call last):
File "/home/user/Temp/IRCBOT/./bot.py", line 14, in <module>
irc.send('USER ' + botnick + ' localhost localhost :This is a bot!\n')
TypeError: a bytes-like object is required, not 'str'
Можно добавить b
перед строкой и использовать функцию bytes()
для преобразования строк в набор байтов, но я лучше воспринимаею код,
когда используется метод encode
.
irc.send(b'USER ' + bytes(botnick, encoding = 'utf-8') + b' localhost localhost :This is a bot!\n')
И в конечном итоге получаем сообщения от сервера.
while True:
text = irc.recv(2040)
print(text)
Ниже представлю полный листинг программы.
#!/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.
# !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
Потребление памяти
На моей конфигурации скрипт потребляет примерно 6,8-7.0Mb.
Linux porteus.example.net 5.18.8-porteus #1 SMP PREEMPT_DYNAMIC Sat Jul 2 10:05:31 MSK 2022 x86_64
Intel(R) Core(TM)2 Duo CPU T6570 @ 2.10GHz GenuineIntel GNU/Linux
Тот же самый код, но на Crystal потребляет 1.7Mb памяти.