IRC Backends#

sopel.irc.abstract_backends#

sopel.irc.abstract_backends defines the IRC backend interface.

Warning

This is all internal code, not intended for direct use by plugins. It is subject to change between versions, even patch releases, without any advance warning.

Please use the public APIs on bot.

class sopel.irc.abstract_backends.AbstractIRCBackend(bot: AbstractBot)#

Abstract class defining the interface and basic logic of an IRC backend.

Parameters:

bot (sopel.bot.Sopel) – a Sopel instance

Some methods of this class MUST be overridden by a subclass, or the backend implementation will not function correctly.

decode_line(line: bytes) str#

Decode a raw IRC line from bytes to str.

abstract irc_send(data: bytes) None#

Send an IRC line as raw data.

Parameters:

data (bytes) – raw line to send

This method must be thread-safe.

abstract is_connected() bool#

Tell if the backend is connected or not.

log_exception() None#

Log an exception to sopel.exceptions.

The IRC backend must use this method to log any exception that isn’t caught by the bot itself (i.e. while handling messages), such as connection errors, SSL errors, etc.

abstract on_irc_error(pretrigger: PreTrigger) None#

Action to perform when the server sends an error event.

Parameters:

pretrigger – PreTrigger object with the error event

On IRC error, if bot.hasquit is set, the backend should close the connection so the bot can quit or reconnect as required.

prepare_command(*args: str, text: str | None = None) str#

Prepare an IRC command from args and optional text.

Parameters:
  • args – arguments of the IRC command to send

  • text – text to send with the IRC command (optional keyword argument)

Returns:

the raw message to send through the connection

From the IRC Client Protocol specification, RFC 2812 § 2.3:

IRC messages are always lines of characters terminated with a CR-LF (Carriage Return - Line Feed) pair, and these messages SHALL NOT exceed 512 characters in length, counting all characters including the trailing CR-LF. Thus, there are 510 characters maximum allowed for the command and its parameters. There is no provision for continuation of message lines.

The length in the RFC refers to the length in bytes, which can be bigger than the length of the Unicode string. This method cuts the message until its length fits within this limit of 510 bytes.

The returned message contains the CR-LF pair required at the end, and can be sent as-is.

abstract run_forever() None#

Run the backend forever (blocking call).

This method is responsible for initiating the connection to the server, and it must call bot.on_connect once connected, or bot.on_close if it fails to connect.

Upon successful connection, it must run forever, listening to the server and allowing the bot to use send_command() in a thread-safe way.

send_command(*args: str, text: str | None = None) None#

Send a command through the IRC connection.

Parameters:
  • args – IRC command to send with its argument(s)

  • text – the text to send (optional keyword argument)

Example:

# send the INFO command
backend.send_command('INFO')
# send the NICK command with the argument 'Sopel'
backend.send_command('NICK', 'Sopel')
# send the PRIVMSG command to channel #sopel with some text
backend.send_command('PRIVMSG', '#sopel', text='Hello world!')

Note

This will call the sopel.bot.Sopel.on_message_sent() callback on the bot instance with the raw message sent.

send_join(channel: str, password: str | None = None) None#

Send a JOIN command to channel with optional password.

Parameters:
  • channel – channel to join

  • password – optional password for protected channels

send_kick(
channel: str,
nick: str,
reason: str | None = None,
) None#

Send a KICK command for nick in channel .

Parameters:
  • channel – the channel from which to kick nick

  • nick – nickname to kick from the channel

  • reason – optional reason for the kick

send_nick(nick: str) None#

Send a NICK command with a nick.

Parameters:

nick – nickname to take

send_notice(dest: str, text: str) None#

Send a NOTICE command to dest with text.

Parameters:
  • dest (str) – nickname or channel name

  • text (str) – the text to send

send_part(channel: str, reason: str | None = None) None#

Send a PART command to channel.

Parameters:
  • channel – the channel to part

  • text – optional text for leaving the channel

send_pass(password: str) None#

Send a PASS command with a password.

Parameters:

password – password for authentication

send_ping(host: str) None#

Send a PING command to the server.

Parameters:

host – IRC server host

A PING command should be sent at a regular interval to make sure the server knows the IRC connection is still active.

send_pong(host: str) None#

Send a PONG command to the server.

Parameters:

host – IRC server host

A PONG command must be sent each time the server sends a PING command to the client.

send_privmsg(dest: str, text: str) None#

Send a PRIVMSG command to dest with text.

Parameters:
  • dest – nickname or channel name

  • text – the text to send

send_quit(reason: str | None = None) None#

Send a QUIT command.

Parameters:

reason – optional text for leaving the server

This won’t send anything if the backend isn’t connected.

send_user(user: str, mode: str, nick: str, name: str) None#

Send a USER command with a user.

Parameters:
  • user – IRC username

  • mode – mode(s) to send for the user

  • nick – nickname associated with this user

  • name – “real name” for the user

sopel.irc.backends#

sopel.irc.backends defines Sopel’s IRC connection handlers.

Warning

This is all internal code, not intended for direct use by plugins. It is subject to change between versions, even patch releases, without any advance warning.

Please use the public APIs on bot.

class sopel.irc.backends.AsyncioBackend(
bot: AbstractBot,
host: str,
port: int,
source_address: tuple[str, int] | None,
server_timeout: int | None = None,
ping_interval: int | None = None,
use_ssl: bool = False,
certfile: str | None = None,
keyfile: str | None = None,
verify_ssl: bool = True,
ca_certs: str | None = None,
ssl_ciphers: list[str] | None = None,
ssl_minimum_version: ssl.TLSVersion = ssl.TLSVersion.TLSv1_2,
**kwargs: Any,
)#

Bases: AbstractIRCBackend

IRC Backend implementation using asyncio.

Parameters:
  • bot – an instance of a bot that uses the backend

  • host – hostname/IP to connect to

  • port – port to connect to

  • source_address – optional source address as a tuple of (host, port)

  • server_timeout – optional time (in seconds) before the backend reach a timeout (defaults to 120s)

  • ping_interval – optional ping interval (in seconds) between last message received and sending a PING to the server (defaults to server_timeout * 0.45)

  • use_ssl – if the connection must use SSL/TLS or not

  • certfile – optional location of the certificates; used when use_ssl is True

  • keyfile – optional location to the key file for certificates; used when use_ssl is True and certfile is not None

  • verify_ssl – if the certificates must be verified; ignored if use_ssl is not True

  • ca_certs – optional location to the CA certificates; ignored if verify_ssl is False

  • ssl_ciphers – the OpenSSL cipher suites to use

  • ssl_minimum_version – the lowest SSL/TLS version to accept

get_connection_kwargs() dict#

Return the keyword arguments required to initiate connection.

irc_send(data: bytes) None#

Send an IRC line as raw data.

Parameters:

data (bytes) – raw line to send

This method must be thread-safe.

is_connected() bool#

Tell if the backend is connected or not.

on_irc_error(pretrigger: PreTrigger) None#

Action to perform when the server sends an error event.

Parameters:

pretrigger – PreTrigger object with the error event

On IRC error, if bot.hasquit is set, the backend should close the connection so the bot can quit or reconnect as required.

async read_forever() None#

Main reading loop of the backend.

This listens to the reader for an incoming IRC line, decodes the data, and passes it to bot.on_message(data), until the reader reaches the EOF (i.e. connection closed).

It manages connection timeouts by scheduling two tasks:

  • a PING task, that will send a PING to the server as defined by the ping interval (from the configuration)

  • a Timeout task, that will stop the bot if it reaches the timeout

Whenever a message is received, both tasks are cancelled and rescheduled.

When the connection is closed, the reader will reach EOF, and return an empty string, which in turn will end the coroutine.

See also

The decode_line() method is used to decode the IRC line from bytes to str.

run_forever() None#

Run forever.

async send(data: bytes) None#

Send data through the writer.

class sopel.irc.backends.UninitializedBackend(bot: AbstractBot)#

Bases: AbstractIRCBackend

IRC Backend shim to use before the bot has started connecting.

Parameters:

bot – an instance of a bot that uses the backend

This exists to intercept attempts to do “illegal” things before connection, like sending messages to IRC before we even have a socket.

irc_send(data: bytes) None#

Dummy method to send IRC data.

Since it is impossible to send data to IRC without an IRC connection, this implementation raises an error if it is ever called.

Note

Plugins will likely never need to call this method directly, but many public API methods of bot call it.

Plugin code that can be triggered by anything that isn’t an IRC event/message should check the bot.connection_registered flag before calling any bot method that modifies IRC state.

is_connected() bool#

Check if the backend is connected to an IRC server.

Always returns False: This backend type is never connected.

Jobs (interval()) or other time-based triggers can be invoked before the bot is finished initizalizing, even before it has begun the IRC connection process. We need to provide a reliable way for those triggers to abort early if they need a connection.

Note

Your plugin code doesn’t need to call this directly; unless your plugin does something during connection setup, it should check the bot.connection_registered flag, which also takes into account whether the IRC connection is ready to accept normal commands like PRIVMSG.

on_irc_error(pretrigger: PreTrigger) None#

Dummy IRC error handler.

Since it should be impossible to receive an error from IRC when there is no server connection, this implementation raises an error if it is ever called.

run_forever() None#

Dummy connection setup method.

Since this implementation is a placeholder and does not actually connect to IRC, it raises an error if it is ever called. The bot should switch to an appropriate backend type before trying to connect; not doing so is a bug.