TYLERBOT

Project leader: doug

About this project

An IRC bot framework that features dynamically loadable and unloadable Python models, an event driven architecture, multi-network support, SSL support, authentication mechanisms, and remote-modules.

Tyler is the mascot of the neverfear.org IRC channel and runs modules that are tied-in with a lot of our web based software.

What is Tyler?

Don't you mean who? Tyler Durden of course!

To put it simply, it's yet another IRC bot. So what do we think makes this one special? Aside from being our IRC moscot the framework is feature rich and powerful. A module developer can write Tyler bot modules in 10 minutes.

But why yet another IRC bot?

Largely because we wanted a simple and fun way to tie our IRC activities to our web activities. Tyler is now tied to several of our web sites, including our image paste, our text paste and soon the neverfear.org website itself. This allows us to be notified about activity on our sites and also allows us to interact with them over IRC. Namely to make paste bin pastes or upload images.

But moreover, I wanted to create something really powerful and cute for geeks and IRC goers to enjoy playing with. It is a competitor against eggdrop and I think the features and the ease within which modules can be developed for it will make it a worthy adversary... when I release something.

What features does Tyler have?

As of today the implemented features are:

  • Dynamically loadable and unloadable Python based modules
  • A simple XML configuration
  • Multi network support
  • Debugging tools
  • Authenication modules that can be used to determine if a person is who they say they are
  • Several default commands and tools included in the out-of-the-box modules
  • A module full of Fight Club quotations that Tyler delivers to the channel throughout the day
  • XML-RPC support to link modules to other services
  • Remote modules - these are like webservices but can add their own event handlers and influence the bots execution
  • XML-RPC level authentication to ensure the remote module you are communicating with is authorised to influence Tyler's execution
  • Multi-language model support to allow people to write modules in C, Perl, PHP, and many more using the XML-RPC interface

Planned features still to come:

  • Even more developers API
  • Uh.. developer documentation.. I promise!

Downloads

The project isn't yet ready for release. I am trying to find time to work on all of my projects and Tyler is certainly one loved by the folks at irc.neverfear.org.

Below are the available downloads for this project. It's in a relatively stable pre-alpha state. Since I will be prioritising other projects for the foreseeable future I thought it would be nice for people to take advantage of the features in tyler as is.

Tyler 0.2 bundle

Documentation

For those who've gotten their hands on a copy of Tyler already, you'll be wanting documentation. All I can say is, when the first released packages go out I'll immediately begin working on this. Stay tuned!

A sample TylerBot module in Python

Here we see a sample module that has two commands, defines a custom event of it's own, and handles two events (including the custom event). This demonstrates a lot of basic functionality in one go. This module will be available with the 1.0 distribution.

import Commands
import Utility
import Events
import ParamConstants
 
# These are also used as part of tylers builtin
# "version", and "author" commands
__author__ = "doug@neverfear.org"
__version__ = "1.0"
 
def SamplePrivmsgEventHandler(params):
    # Get the parameters
    name       = params[ParamConstants.NAME]
    message    = params[ParamConstants.MESSAGE]
    network    = params[ParamConstants.NETWORK]
    returnpath = params[ParamConstants.RETURNPATH]
 
    source = Utility.splitsource(name)
 
    if message == "chickensoup":
        # If somebody says "chickensoup" in a channel
        # tyler is in or via private message
        # Then trigger the custom event
        CustomParams = {
                        "example": "this is some example event parameters",
                        "target": returnpath,
                        "network": network
        }
        Events.EventManager.ProcessEvent("a custom event", CustomParams)
    else:
        # Echo the message back to the sender
        network.Privmsg(returnpath, "%s: %s" % (source["nick"], message))
 
def SampleCustomEventHandler(params):
    # Send the /example/ text to /target/ on /network/.
    params["network"].Privmsg(params["target"], params["example"])
 
def SampleCommandHandler(params):
    # This comment is used as the default help text for a command.
    # In this module test2 has a specific text help defined near the
    # bottom of this file. However test1 has no specific help text,
    # in this case "A sample command." is used as it's help text.
    """A sample command."""
 
    # Get the parameters
    botcmd     = params[ParamConstants.USERCMD]
    botargs    = params[ParamConstants.USERARGS]
    returnpath = params[ParamConstants.RETURNPATH]
    network    = params[ParamConstants.NETWORK]
 
    # Identify what command was used and list the arguments
    network.Privmsg(returnpath,
                    "Command '%s' invoked! Arguments: %s" % (botcmd, botargs))
 
# Add a basic command
Commands.AddCommand("test1", SampleCommandHandler)
# Add some help and usage text to a command
Commands.AddCommand("test2", SampleCommandHandler,
                             UsageText = "test2",
                             HelpText = "Some help text")
# Add an event handler for all PRIVMSG's.
Events.EventManager.AddEventHandler("onPrivmsg",
                                    SamplePrivmsgEventHandler)
 
# Define a custom event
Events.EventManager.AddEvent("a custom event")
# Add a handler for the custom event
Events.EventManager.AddEventHandler("a custom event",
                                    SampleCustomEventHandler)

A sample TylerBot module in C

Here we see a sample module written in C that has a single command defined. This module can be loaded in exactly the same way as any other module.

#include <Python.h>
 
/*
 * Prototypes.
 */
PyMODINIT_FUNC initSampleModule_C(void);
static PyObject * MarlaSingerHandler(PyObject *self, PyObject *args);
 
 
/*
 * List of methods defined here.
 */
static PyMethodDef ModuleMethods[] = {
    {"MarlaSingerHandler", MarlaSingerHandler, METH_VARARGS,
     "An example Tyler command."},
    {NULL, NULL, 0, NULL}
};
 
/*
 * Module name.
 */
static char * ModuleName = "SampleModule_C";
 
 
/*
 * Module initialisation function.
 */
PyMODINIT_FUNC initSampleModule_C(void) {
    PyObject * MyModule;
    // Initial this module.
    MyModule = Py_InitModule(ModuleName, ModuleMethods);
    if (MyModule == NULL) {
        return;
    }
 
    // Import the Commands Tyler module.
    PyObject * CommandsModule = PyImport_Import(
                                           PyString_FromString("Commands"));
 
    if (CommandsModule) {
        if(PyObject_HasAttrString(CommandsModule, "AddCommand")) {
 
            // Get a reference to the AddCommand function of the Commands
            // module.
            PyObject * AddCommandFunc = PyObject_GetAttrString(
                                              CommandsModule, "AddCommand");
 
            // Get a reference to our handler function defined in this
            // module.
            PyObject * MarlaSingerHandlerFunc = PyObject_GetAttrString(
                                            MyModule, "MarlaSingerHandler");
 
            // Compile the arguments.
            PyObject * ArgTuple = Py_BuildValue("sO", "marla",
                                                    MarlaSingerHandlerFunc);
 
            // Add a command to Tyler. This function in Python:
            // import Commands
            // Commands.AddCommand("marla", MarlaSingerHandler)
            PyObject_Call(AddCommandFunc, ArgTuple, NULL);
 
        }
    }
}
 
/*
 * Our command handler function.
 */
static PyObject * MarlaSingerHandler(PyObject *self, PyObject *args) {
 
    // Get the first parameter.
    PyObject * params = PyTuple_GetItem(args, 0);
 
    if (PyDict_Check(params)) {
        // Get the network object.
        PyObject * NetworkObject = PyDict_GetItem(params,
                                            PyString_FromString("network"));
 
        // Get the return path string.
        PyObject * ReturnPathString = PyDict_GetItem(params,
                                         PyString_FromString("returnpath"));
 
        // Get a reference to the Privmsg method of the network object.
        PyObject * PrivmsgFunc = PyObject_GetAttrString(NetworkObject,
                                                                 "Privmsg");
 
        // Compile a message to send to the channel or user.
        PyObject * SendMsgString = PyString_FromString(
                     "I haven't been f***ed like that since grade school.");
 
        // Compile the arguments.
        PyObject * ArgTuple = Py_BuildValue("OO", ReturnPathString,
                                                             SendMsgString);
 
        // Call the Privmsg routine. This function in Python:
        // params["network"].Privmsg(params["returnpath"], "I haven't ...")
        PyObject_Call(PrivmsgFunc, ArgTuple, NULL);
    }
 
    return Py_BuildValue("");
}

For those interested the same functionality could be implemented in this module:

import Commands
def MarlaSingerHandler(params):
    network = params["network"]
    returnpath = params["returnpath"]
    network.Privmsg(
                    returnpath,
                    "I haven't been f***ed like that since grade school."
                    )
Commands.AddCommand("marla", MarlaSingerHandler)
Powered by Debian, Jack Daniels, Guinness, and excessive quantities of caffeine and sugar.