Blog/content/posts/2022/python-irc-bot.md

7.2 KiB
Raw Blame History

title date draft tags
IRC бот на Python 3 2022-09-23T22:54:34+03:00 false
python
irc
tutorial

Введение

Это руководство своего рода обобщение уже размешённой в сети информации, по написанию 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 памяти.

Используемые материалы

  • Internet Relay Chat Protocol RFC [Ссылка]
  • How do i program a simple IRC bot in python? [Ссылка]
  • Краткое описание протокола IRC и пример бота [Ссылка]
  • Простейший IRC-бот на Python, а также при чем тут Slack, Gitter и прочие веб-чаты [Ссылка]