My IRC bot goals
- Parse, cache, and deliver updated Coronavirus statistics - Country and States.
- Be able to stash and retrieve links for quick access.
- Be able to shorten links using Bit.ly API.
- Be able to define words.
… but, for the sake of this note, I wish to keep it as simple as possible and stick to basic features such as parsing messages, sending message to a user in a channel, and sending private message directly to a user.
Connecting to the IRC Network
The base functionality that we need for this bot to connect to the IRC network consists of utilizing a low-level networking interface called
I decided to go with the raw text port to connect to the IRC network without SSL because it is a simple bot, nothing too complex and I became too lazy to set up SSL for this project.
Sending our bot’s credentials for identification
Once we connect to the IRC Network, the network requires a person or a bot to send their credentials to the network for identification. We first need to register our bot and the nickname of our choice before we move forward. The reason, if not obvious, we do not want our bot to have varying and random nickname which makes it completely inaccessible. I decided to register a nickname
PS[bot] for my bot.
This is the base IRC bot, so far we have connected to the IRC network and identified ourselves in the network.
Receiving, parsing, and handling commands
A bot that does nothing but identify itself to the IRC network is useless unless, it can fulfill the commands we feed it. In order for it to fulfill, we need to capture (tap into the socket stream) and parse the commands accordingly. In order to do that, we need to read the stream in an infinite loop (this isn’t event based therefore the need for
loop). In order to keep this note (self-tutorial) simple, I decided not to utilize any classes, keeping the script bare-bone with no standard structure.
message variable stores the parsed but raw messages. The most important thing that we need to parse after connecting to the IRC network is to handle a message with header
PING in simple terms is the implication that IRC protocol uses to keep track and test whether a client is connected to the IRC network or not. When the IRC network sends a message,
PING :<something>, we must reply with the message header
PONG :<some_message> to let the server know our bot is alive, active, and kicking.
I decided to create a function to handle this
PONG relay to keep it clear. Now, continuing our parsing and handling the messages in our stream under the loop above, we handle
PING and prioritize it because staying available and accessible is important for a bot.
This is pretty much the solid foundation of a bot, join the network, identify itself, respond to
PONG and handle other commands (if necessary).
Joining and Leaving a channel
So far, our bot has not joined any channels, I like to keep things private and allow access to the bot to certain people. If we want our bot to function in a channel, we need to command the bot to join specific channel. A simple channel join function revolves around sending a command
JOIN with channel identifier, for example
A process to command a bot to leave a channel is similar, we utilize
PART command with channel we wish the bot to part, if we want. For example -
PART ##bots :Sorry, gotta go! or something similar. We can also supply multiple channels using
, to separate the channels we wish to part,
PART ##bots,##linux,#python :Sorry, bot overloaded! .
More messages parsing
Continuing the development of our bot, if we wish to better the bot, we need to be able to identify the
message. Continuing the parsing under loop.
What we have done here is that we parsed one line of raw message in our stream, however, IRC follows standard protocol and specifications that we must refer to, in order to properly parse the messages. A line of message is in a format of
:<nick_of_the_sender>!<hostname> PRIVMSG <recipient> :<message>. That is what we parsed above to get the sender’s nickname, in
user variable. If I were to send a private message to my bot, the raw message that the bot receives would be in format of
:Scarecr0wfirstname.lastname@example.org (PMS) PRIVMSG PS[bot] :Hello.
Similarly, if I were to send a message in a channel that my bot has joined, for example -
##bots, my bot would receive message in format of
:Scarecr0wemail@example.com (PMS) PRIVMSG ##bots :Hello. That is one reason I parsed
channel from the raw message and initialized it in a variable for later use. Everything after
PRIVMSG ... is the message, an actual conversation text.
Let’s continue the message parsing and respond to specific commands.
To simplify it further, I decided to create a separate function to handle sending the messages to the intended channel or direct/private message (DM/PM) the user.
That is basically it, for basic IRC bot interaction and message handling. There are definitely endless features we can implement.
Here is my bot in action.