Skip to content
Luke Rogers edited this page Jan 18, 2015 · 68 revisions

Writing Plugins for CloudBot Refresh

Writing plugins for CloudBot is simple! This guide seeks to explain everything you need to do to.

If you have any trouble understanding the guide, come chat with us in the #cloudbot IRC channel on irc.esper.net.

Plugin structure

Every plugin written for CloudBot is essentially a python file located in the plugins directory. The plugin must be written in python 3, and the file name must end in .py to be detected by CloudBot.

Each plugin file may contain any number of hooks, to create commands, listen to events, watch input for certain patterns, or control other plugins.

Detailed first-command guide

If this is your first time writing plugins for CloudBot, check out the Writing your first command plugin guide.

Hook types

Here are a few example hook types. We'll go into more detail later, but this lists all the ones you can use

Command Hook

The command hook can be used to register a command in CloudBot.

Here's an example command which will return the input given to it, added to itself.

from cloudbot import hook


@hook.command()
def echo(text):
    return text + " " + text

If you want hook to respond to multiple commands, you can pass them as arguments to the hook.

from cloudbot import hook


@hook.command("echo", "hello")
def echo(text):
    return text + " " + text

With this example, the hook will be triggered by .echo or .hello

Regex Hook

@hook.regex(myregex)

Takes an argument corresponding to the regex string, or compiled regex, followed by optional flags. Each line of chat is matched against the provided regex pattern; if the bot finds a match, the hooked function will be called with the match object.

Here's an example that will match the regex ^Hi TestBot(!|\?|\.)?$, and will return Hi! to the user saying it.

from cloudbot import hook


@hook.regex(r"^Hi TestBot(!|\?|\.)?$")
def hi_hook(match):
    return "Hi!"

IRC_RAW Hook

@hook.irc_raw(myevent)

IRC_RAW hooks are called whenever a specific IRC command is issued. For example, to run some code whenever a user talks, you can use 'PRIVMSG' as the argument. Using '*' as the argument will hook all IRC activity.

Some useful events to hook onto are:

  • PRIVMSG - called when a user speaks
  • KICK - called when a user is kicked
  • NICK - called when a user changes nick
  • 004 - called when the bot is connected to the network and ready to accept input

The first argument returned for 'PRIVMSG' be a two-element list of the form ["#channel", "text"]. Details on what other types of event return will be added soon.

Here's an example IRC_RAW hook that will make the bot join two password-protected channels, when the bot starts up.

Note the "conn" argument to this hook. That's optional for hooks, and is just there so that conn.send can be run. We'll go into more detail into it, and other arguments below.

from cloudbot import hook


@hook.irc_raw(“004”)
def onready(paramlist, conn):
    conn.send("JOIN #channel1 password1")
    conn.send("JOIN #channel2 password2")

Sieve Hook

@hook.sieve()

All sieve hooks loaded are called whenever before other command, event or regex hook is called. Sieves can be used to control, or filter hooks.

Here's an example sieve which won't let any commands be used in the channel '#channel1'.

Note that any method using @hook.sieve, unlike other hooks, must take exactly 3 arguments.

The first argument is 'bot', the second is 'even', and the third is 'plugin'.

If the sieve returns the same event that it was given, the plugin continues normally. If None is returned, then the plugin running is canceled, and the command/regex/event is not run.

from cloudbot import hook


@hook.sieve()
def mysieve(bot, event, plugin):
    if plugin.type == "command":  # if this is a command
        if event.chan == "#channel1":  # if the channel is #channel1
            return None  # return None, canceling the action

    return event # return event, so that the command will be run

Shared Arguments

Part of the cool thing with CloudBot plugin hooks, is that what arguments your plugin is given, depends on the names of the arguments.

So if I define a command, def mycommand(text), all it's given is the 'text' argument.

If I define, def mycommand(text, bot, chan), then it's given the 'text' argument, the 'bot' argument, and the 'chan' argument.

This can be done for any hook, except sieve hooks. Sieve hook parameters are fixed, but all other hooks can have dynamic arguments like this.

Here are the different arguments you can ask for, and what they do:

Name Type What it is What hooks can use it
text String Arguments to the command command
match Match Regex match regex
chan String Channel the command/regex is in all
nick String Nick of the user using the command/regex all
server String Server the command/regex is used on all
db SQLAlchemy database connection Database connection, more info will be added later all
event Event "Event" object, containing parameters as attributes all
conn BotConnection Server-specific connection object all
bot CloudBot Main bot object all

There are also a few functions which you can ask for, and get passed as parameters. They are like the above, but are actually functions, and can be called with name(parameters).

Here are some different methods you can use:

Name Usage What it does
message message("hi") Messages the channel
reply reply("hi") Sends a reply to the channel, prefixed with (Nick)
action action("something") Performs an action in the channel, like /me
ctcp ctcp("msg", "VERSION", nick) Sends a CTCP message to the specified user
notice notice("Incorrect args") Notices a user
has_permission has_permission("botcontrol") Checks if the user has a specified permission (bot-specific)

Here's an example command which uses the 'message' function to raw message something.

from cloudbot import hook


@hook.command()
def mycmd(text, message):
    message("Hi people, someone said '" + text + "'")

Permissions

Sometimes you want to define a command, but don't want just anyone to have access to it.

You can specify a 'permission' which anyone wanting to use your command will need, by adding a permissions=["permissionname"] argument to your @hook.command. For example, @hook.command(permissions=["botcontrol"]).

Example command requiring the 'botcontrol' permission:

from cloudbot import hook


@hook.command(permissions=["botcontrol"])
def mycmd(text, message):
    message(text)

This command just raw messages the input text. This isn't something you want to give to anyone though, so only people with access to botcontrol can use it.

Permissions are mainly controlled in the config, under each connection object. There are predefined groups, like 'admins', which have certain permissions. 'admins' has access to botcontrol by default, so you can add yourself to it to gain access to this command.

There's also a utility command that you can use to add a user to a group, which can be accessed like so:

<Myself> TestBot, adduser Myself!~myself@my.host.example.com admins

This will add the mask Myself!~myself@my.host.example.com to the group admins.