Communicating with clients is the whole point of an IRC server, so you want to make sure you’re doing it properly. Today, we’ll be looking at receiving messages from a client and sending messages to the client.
Users in Twisted IRC are represented as subclasses of the IRC class
.
This works as the protocol for your Factory class. It will also give you IRC features (like automatically parsing incoming lines) without you having to implement them yourself. The rest of this guide assumes this setup.
Messages are sent to users using the user object’s sendMessage
method.
The basic syntax for sending messages to users is as follows:
user.sendCommand("COMMAND", (param1, param2), server.name)
The prefix keyword argument is optional, and it may be omitted to send a message without a prefix (for example, the ERROR command). The command is whatever command you plan to send, e.g. “PRIVMSG”, “MODE”, etc. All arguments following the command are the parameters you want to send for the command. If the last argument needs to be prefixed with a colon (because it has spaces in it, e.g. a PRIVMSG message), you must add the colon to the beginning of the parameter yourself. For example: .. code-block:: python
user.sendCommand(“PRIVMSG”, (user.nickname, “:{}”.format(message)), sendingUser.hostmask)
Twisted also allows sending message tags as specified in IRCv3.
Let’s say, for example, that your server has a feature to play back a little bit of previous channel content when someone joins a channel. You want a way to tell people when this message occurred. The best way to provide this information is through the server-time specification.
Let’s say you’re storing past messages in a channel object in some structure like this:
channel.pastMessages = [
("I sent some text!", "author!ident@host", datetime object representing the when the message was sent),
("I did, too!", "someone-else!ident@host", another datetime object)
]
Your actual implementation may vary. I went with something simple here. The times of the messages would be generated using something like datetime.utcnow()
when the message was received.
Tags are passed as a list of tuples. If you’re sending a number of tags, you may have an existing tag dictionary. You can simply add to it (assuming message
is the loop variable for channel.pastMessages above):
sendingTags["server-time"] = "{}Z".format(message[2].isoformat()[:-3])
This will generate the required time format and add it to the tag dictionary. The last three characters that we remove are the microseconds; removing the last three digits changes the precision to milliseconds.
Once your tags are collected, you can send the message. The tag dictionary is passed using the tags
argument (in the same loop as above):
user.sendCommand("PRIVMSG", (user.nickname, message[0]), message[1], sendingTags)
Twisted Words will handle receiving messages and parsing lines into tokens. The parsed messages are passed into your command through the user’s handleCommand
method.
The default IRC handleCommand method calls the irc_COMMAND
method when it receives the command COMMAND
, and it calls irc_unknown if the method for the command received isn’t defined.
from twisted.words.protocols import irc
class IRCUser(irc.IRC):
# possibly other definitions here
def irc_unknown(self, prefix, command, params):
self.sendCommand(irc.ERR_UNKNOWNCOMMAND, (command, ":Unknown command"), server.name)
def irc_PRIVMSG(self, prefix, params):
# do some stuff to handle PRIVMSG for your server's setup
# lots of other command definitions
If you have a server setup that doesn’t allow you to do this (e.g. a modular server program), you may, of course, override the handleCommand function to route commands to your own handlers.
This has not yet been implemented.