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.
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.
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.
As of today the implemented features are:
Planned features still to come:
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.
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!
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)
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)