Skip to content

Anatomy of an IRC Event

JR edited this page Mar 3, 2023 · 5 revisions

Server strings

Information from the IRC server comes in lines of humanly readable text.

:[email protected] PRIVMSG #channel :Hello world!

dialect parses those and populates an IRCEvent struct, with members containing discrete bits of information gleaned from the server line. It essentially picks those out and sorts them for easier use. Importing projects don't have to deal with the raw server strings directly; instead they deal with the event structs passed to them. It is an abstraction layer.

Layout

struct IRCEvent
{
    enum Type { /* ... */ }

    Type type;
    string raw;
    IRCUser sender;
    IRCUser target;
    string channel;
    string content;
    string[16] aux;
    string tags;
    uint num;
    Nullable!long[16] counts;
    long time;
    string errors;

    version(TwitchSupport)
    {
        string emotes;
        string id;
    }
}
struct IRCUser
{
    enum Class { /* ... */ }

    string nickname;
    string realName;
    string ident;
    string address;
    string account;
    long updated;
    Class class_;

    version(TwitchSupport)
    {
        string displayName;
        string badges;
        string colour;
    }
}

Member descriptions

The IRCEvent:

  • type, or of what kind an event is. There is a big table of several hundred total types of events, though most are never really encountered. Event types include things like CHAN for channel messages, QUERY for private messages, NICK for when someone changes their nickname, TOPIC when someone chages topic, etc.

  • raw, or a copy of the raw server string. This is kept not only for debugging purposes, but because most other string members are slices of the raw string.

  • sender, an IRCUser representing the person from whom the event originated. If the sender has no nickname, the sender is the server itself.

  • target, likewise an IRCUser though representing the target of the event, where such makes sense.

  • channel, or in which channel the event took place, where applicable. It can also refer to which channel an event is targeted towards, such as the target of an INVITE. In either case it is always a channel, and it will be empty if the event doesn't really relate to any channel, such as a private message QUERY.

  • content, or the main body of an event. For instance, in a CHAN or QUERY event this is the message sent. In a KICK event, it is the reason given. long altcount;

  • aux, or simply auxiliary information pertaining to the event. This is an array of 16 strings, and what it contains strongly differs between different event types. In a MODE event where someone changes the mode of something in a channel, content may house the address mask of a user, leaving aux[0] to contain the mode change itself, such as +o for giving someone channel operator status.

  • tags, or the IRCv3 tags[1] that accompany the message. These are prepended before the actual server strings on some servers; mainly Twitch, where they contain detailed information about the event.

  • num, or the numeric value of a numeric type. Some types don't come in easy human-readable text but rather as a three-figure number, which we parse into something that is readable and easy to reason about. The number itself remain in the num member.

  • counts, or a general Nullable counters in the context of the event type. In RPL_CREATIONTIME events, counts[0].get it is the UNIX time of when a channel was created.

  • time, or simply a timestamp of when the event triggered. Expressed in UNIX time.

  • errors, or a string with whatever errors were encountered during parsing. In a normal build these are also printed out as they are encountered mid-parsing, but they are also always stored here for other use.

  • emotes (version TwitchSupport), or a listing of which Twitch emotes are present in the content string, and where they are.

  • id (version TwitchSupport), or the alphanumerical id of the message on Twitch servers. Mostly useless.

The IRCUser:

  • nickname, simply the nickname of the user in question.
  • realName, or surprisingly, what is usually referred to as the "real name" field. Also known as GECOS.
  • ident, or the Identification protocol (IDENT) identifier of the user. The server doesn't have one but all other users do on conventional servers.
  • address, or either the hostname or IP of the sender, depending on availability. All users have this, though some network services like NickServ may have theirs artificially changed. Some servers also provide cloaks that mask your real address, to provide anonymity and to show affiliation with projects. If the IRCUser is the server, the server's address is stored here, and the nickname is blank.
  • account; what services account the user is logged on as. It is the main way for the bot to uniquely identify people, as nicknames can be changed freely on conventional servers (i.e. not Twitch).
  • updated, or the timestamp of when this user was last the target of a server WHOIS query.
  • class_, or what classifier the user has. It can be anyone, whitelist, blacklist, operator or admin, each of which have a privilege level that is matched with what a command is defined to require to process. (The last case special is not to be relied upon and may be removed in future releases.)
  • displayName (version TwitchSupport), the display name of the user. On Twitch servers users may have an alternative representation alongside their nicknames, even if it's just the same but cased. This is stored here.
  • badges (version TwitchSupport), or what Twitch "badges" a user has.
  • colour (version TwitchSupport), or what colour the sender name should be printed in. This is another thing on Twitch servers, where users are assigned an RGB username colour.

Slices

With some exceptions, all string members are slices of the IRCEvent.raw string. A string is an array of characters; simply put, some row of characters in the computer memory. A slice is a section of an array, with different starting and stopping points, but still of the same array in memory. The immediate benefit of using slices as opposed to making a new array copy for each string member is performance. There's only ever that one array allocated, and the string members simply point at different parts of it. There is a very well-written chapter on slices in the Programming in D book[2] by Ali Cehreli, and it's freely available on the web.

[1]: http://ircv3.net/specs/core/message-tags-3.2.html

[2]: http://ddili.org/ders/d.en/slices.html

Clone this wiki locally