Plugins

Basic Plugins

Writing brutal plugins is meant to be easy. By nature, a bot responds to events within a chat system. Everything brutal sees is an Event object and it is possible to write plugins that only respond to specific !command in a channel or an event parser that responds to certain or all types of events.

basic commands

If you just want to make a command that the bot will respond to, all you have to do is:

from brutal.core.plugin import cmd
@cmd
def ping(event):
    return 'pong, got {0!r}'.format(event)

@cmd
def testargs(event):
    return 'you passed in args: {0!r}'.format(event.args)

basic events

If you want to register an parser to handle events, you can easily do this as well.:

from brutal.core.plugin import event

@event
def test_event_parser(event):
    return 'EVENT!!! {0!r}'.format(event)

This will respond to every action a bot sees in a channel with a message.

basic matching

It is also possible to write a parser that responds to a given regex.:

from brutal.core.plugin import match

@match(regex=r'^hi$')
def matcher(event):
    return 'Hello to you!'

This will respond every time someone says hi in the channel.

blocking code

Sometimes its hard to write async code. Rather than limit you to other bot frameworks, brutal has built in support for code that blocks. You simple have to let it know that your code is not async by passing in thread=True.:

import time  # blocking lib
from brutal.core.plugin import cmd, event

@cmd(thread=True)
def sleep(event):
    time.sleep(5)  # blocks
    return 'im sleepy...'

@event(thread=True)
def sleepevent(event):
    time.sleep(7)  # blocks
    return 'SOOOOOO sleepy'

Every time these trigger, they get put into a global thread pool that brutal maintains for you. If your code blocks for too long, you risk the chance of the thread pool getting incredibly backed up so some thought must be put into what you’re blocking for. It is recommended that you try to write asynchronous code using the brutal and twisted utilities.

Plugin Classes

Sometimes a simple function just isn’t enough. If you need to store state with your bot functionality, it is recommended that you extend the BotPlugin class. Every bot that you define within brutal will have its own instance of this class upon startup, each with its own state.

basic use of BotPlugin

import time
from brutal.core.plugin import BotPlugin, cmd, event, match, threaded

class TestPlugin(BotPlugin):
    def setup(self, *args, **kwargs):
        self.log.debug('SETUP CALLED')
        self.count = 0
        self.loop_task(5, self.test_loop, now=False)
        self.delay_task(10, self.future_task)

    def future_task(self):
        self.log.info('testing future task')
        return 'future!'

    @threaded
    def test_loop(self):
        self.log.info('testing looping task')
        return 'loop!'

    def say_hi(self, event=None):
        self.msg('from say_hi: {0!r}'.format(event), event=event)
        return 'hi'

    @threaded
    def say_delayed_hi(self, event=None):
        self.msg('from say_hi_threaded, sleeping for 5: {0!r}'.format(event), event=event)
        time.sleep(5)
        return 'even more delayed hi'

    @cmd
    def runlater(self, event):
        self.delay_task(5, self.say_hi, event=event)
        self.delay_task(5, self.say_delayed_hi, event=event)
        return 'will say hi in 5 seconds'

    @cmd
    def count(self, event):
        self.count += 1
        return 'count {1!r} from class! got {0!r}'.format(event, self.count)

    @cmd(thread=True)
    def inlinemsg(self, event):
        self.msg('sleeping for 5 seconds!', event=event)
        time.sleep(5)
        return 'done sleeping!'

Test Console

In order to ease some of the pain while developing plugins, brutal provides a basic test console for local development.

TODO: add details here.