So the question is, how can developers write modules for tyler? In this document I hope to provide enough resources so developers can easily write their own modules.
Most of tylers modules are python modules. They are wrote in python and natively take advantage of the framework tyler provides. The minimal requirement for a module is simply, python code which does anything that doesn't require user-input from anything except an IRC network. You don't *have* to import anything and you aren't restricted in what you can do.
As part of development of Python modules for tyler, it's recommended you set the python __author__ global variable. This will allow the .author command of tyler to return author information about the module. This is strongly recommended for making a uniform program.
Lets look at an example
import tutil, trod
def helloworld_load(args, env):
# lets... quit in our "hello" world <3
tutil.ircquit(args["sck"], "Good bye cruel world")
trod.addhook("helloworld", "load", helloworld_load)
As soon as this module is loaded, the tyler bot will immidiately quit the IRC network with the reason "Good bye cruel world". Not only does this demonstrate how you write a very simple module using tutil and trod (documented below), but it also illustrates how you should make sure you know what the module you're loading actually does!
Lets see an even simpler example
import sys
sys.system("echo hello everyone on this system! | wall")
This module demonstrates functionality that doesn't even use the IRC bot at all - except to of course load it. It simply executes a shell command on the local machine. It broadcasts a message to all connected terminatals on the local machine saying "hello everyone on this system!". Should note that this is a GNU style command, and probably wont work on most machines, but as a demonstration I hope it conveys precise what you could potentially do with tyler modules.
import trod
trod.addhook(str modulename, str hookevent, function hookhandler)
in the hookhandler 2 arguements must be outlined, the first arguement will contain event-specific arguements, this is also in the list of hookable events below and is of type dict. the other arguement named 'env' is a reference to the calling tyler instance. to see what entities you may access through this see the section on tyler APIdef myhookhandler(args, env):
if for some reason you deside you want to clear all the hooks you have made, you can call clearhooks(). clearhooks() takes one argument which MUST be the name of your module.trod.clearhooks(str modulename)
trod.dohooks(str eventname, dict args, tyler env)
This function may be used to register your own hook events (which you must trigger - see dohooks for how to trigger them).trod.registerhook(str modulename, str eventname)
import trod
def endofroutine(args, env):
print "You are at the end of the example"
trod.registerhook("example", "endofexample")
trod.addhook("example", "endofexample", endofroutine)
trod.dohooks("endofexample", [], None)
Should output:
You are at the end of the example
This table shows all the currently hookable events, along with what arguments are supplied. The naming conversations explained next are used throughout this list.
sck - a socket descriptor assocated with the event
source - a dict object that has 3 elements. source contains an element named "nick", "user", and "host" which corespond to each section of an IRC source string. However, if the source is a server, these 3 elements will not exist, instead a key named "server" will. If you are hooking anything which uses source you should always check if source.has_key("server") to determine the type of message
tberror - a traceback error string
tbvalue - a traceback error value
tbtype - a traceback error type
target - may be a nick or a channel name
message - a data string with the assocated event
chan - a channel name
reason - a part, kick or quit reason string
server - a server name
victim - the nickname of a user in a kick or kill event
modestring - the entire mode string of a mode event. example modestring may be "+obmv kay *!*@*.com tyler"
topic - a new or existing topic string
newnick - only used in the nick even, the new nick of a source
args - used only in the docmd event, is a list of all the tokens seperated by " " after the command character
cmd - is a string that is equal to args[0] of the above named args event argument. This string represents the "command" that is being executed. Only available in the docmds hook
module - the module that has just loaded (or is being unloaded)
returnpath - the entity to send commands 'to' that leads to the source of the hook trigger. that is to say, if the hook was triggered by a channel action, this is the channel, if it was triggered by a PM to the bot, this is that user
Unlike most of the above, there is one arguement that is always provided, this is called caller, and identifies the hook the routine is being called from, allowing hook-handler routines to implement several hooks in one code block.
| Hookable Event | Event args |
|---|---|
| error (when an error in a module is found) |
|
| load (called only when dynamic loading is used) |
|
| unload (called only when dynamic unloading is used) |
|
| ctcp |
|
| docmd |
|
| domsg |
|
| notice |
|
| privmsg |
|
| who |
|
| join |
|
| quit |
|
| part |
|
| invite |
|
| kick |
|
| nick |
|
| topic |
|
| mode |
|
| doaddmember |
|
| doremmember |
|
There is a core module you can import to use various prewrote utilities (we actually would rather you used these since hooks may be added to some of these routines, allowing other modules to work properly). This module is called tutil
import tutil
This is a raw interface to the IRC protocol. You simply send down you IRC protocol line (without the ending new line)tutil.ircsend(sck, data)
tutil.ircsend(validsocket, "NOTICE kay :it's redundant now to send notice's using ircsend() as you can now use ircnotice()")
This is a routine which sends out an IRC PRIVMSG command to the target, and in effect a message to them.tutil.ircmsg(sck, target, message)
tutil.ircmsg(validsck, "#nullnetwork", "howdy")
This is a routine which sends out an IRC PRIVMSG command to the target, and in effect a message to them. The difference between ircmsg() and ircmultimsg() is ircmultimsg() accepts messages which contain new line characters in it.tutil.ircmultimsg(sck, target, message)
tutil.ircmultimsg(validsck, "#nullnetwork", """< brennanOS> heres a conversation starter: Programming in C all day makes me wish I was coding Java instead
< brennanOS> discuss
< orbitz> coding in java makes me wish i was coding in erlang
< AtnNn> you guys code in java?
-!- AtnNn [n=welcome@dsl-*-*.aei.ca] has left ##c []""")
This routine sends an IRC "action" to target. An IRC action on most IRC clients is equivilent to doing /me does something.tutil.ircaction(sck, target, action)
tutil.ircaction(validsck, "#nullnetwork", "dances with a drunk penguin")
This is a routine which sends out an IRC NOTICE command to the target, and in effect a message to them.tutil.ircnotice(sck, target, message)
tutil.ircnotice(validsck, "kay", "You have mail")
This will cause tyler to join chan on socket, scktutil.ircjoin(sck, chan)
tutil.ircsend(validsocket, "#tyler")
Make tyler leave chan,tutil.ircpart(sck, chan, reason)
tutil.ircpart(validsocket, "#tyler", "tyler 2.0 development channel")
Make tyler send a QUIT to the server, thus disconnecting himtutil.ircquit(sck, reason)
tutil.ircquit(validsocket, "Shutting down")
Change the nickname of tylertutil.ircnick(sck, newnick)
tutil.ircnick(validsocket, "Jack") # we all know tyler has multiple personalities!
Kick nick out of chan with the reason, reason.tutil.irckick(sck, chan, nick, reason)
tutil.irckick(validsocket, "#tyler", "b14ck", "You SUCK!") # we all know tyler has multiple personalities!
Kill a user off the IRCd (note: this is reserved for those with an O:Line on the IRCd, and who have "Oper'd up")tutil.irckill(sck, nick, reason)
tutil.irckill(validsocket, "victim", "You are not welcome here") # we all know tyler has multiple personalities!
Send a mode command to targettutil.ircmode(sck, target, modestring)
tutil.ircmode(validsocket, "#tyler", "+cm-o kay")
Op the nicks in nicklist in the channel, chan.tutil.ircop(sck, chan, [nicklist])
tutil.ircop(validsocket, "#tyler", ["kay", "linkd", "will"])
Set bans on the the banmasks in channeltutil.ircban(sck, channel, [banmasks])
tutil.ircban(validsocket, "#tyler", ["*@*.aol.com", "bannednick!*@*", "*!spam@*"])
Set the topic of a chantutil.irctopic(sck, chan, topic)
tutil.irctopic(validsocket, "#tyler", "tyler 2.0 development channel")
Send a who command to target, normally a channel.tutil.ircwho(sck, target)
tutil.ircwho(validsocket, "#tyler") #or tutil.ircwho(validsocket, "kay")
Attempt to oper up (gain server-wide privledges) for the bot.tutil.ircoper(sck, user, opass)
tutil.ircoper(validsocket, "god", "stupidpass")
Invite who to where.tutil.ircinvite(sck, who, where)
tutil.ircinvite(validsocket, "#tyler", "AtnNn")
This routine returns a dictionary of statistics about python code in the current working directory (which unless something is foobared, should be tylers directory, and thus tylers code Layout for the return dict:tutil.tylercodestats()
ret["nfiles"] # the number of files ret["nlines"] # the total number of lines ret["nbytes"] # total number of bytes
This module contains routines that control the user-help system of the bot.
import thelp
This function will return the help data for the first match of cmd within module. None otherwise.thelp.hashelp(module, cmd)
Canviewfunc prototype:ret["cmd"] # the command name ret["module"] # the module name ret["syntax"] # the syntax summary ret["description"] # the description of the command ret["canviewfunc"] # a reference to a function that will calculate if the source address is authorised to see the command
def canviewfunc(source)
thelp.hashelp("somemodule", "somecommadname")
This will register a modules command with the help database. Returns True if added. Returns False if there is already help for that command (use removehelp() to remove)thelp.addhelp(module, cmd, syntax, cmddescription, canviewfunc = helpcanalwaysview):
thelp.addhelp("mockmodule", "tease", "tease <required nick>[,optional nick list]", "This command will tease \x1Frequired nick\x0F and all others in \x1Foption nick list \x0F")
This removes a cmd from the help. If cmd is '' then it behaves exactly like clearhelp and removes all the help for module.thelp.removehelp(module, cmd):
This removes all help for module.thelp.clearhelp(module):
Sends targetsource all the help about cmd he is permitted. If cmd is "" then all the help is sent to targetsource.thelp.gethelp(sck, targetsource, cmd, module):
thelp.gethelp(validsck, {"nick": "kay", "user": "kay", "host": "localhost"}, None, "tyler")
This will request all the builtin ('tyler') help only - no module help will be provided.
Returns the number of commands current registered with the help system Example usage:thelp.helpcnt()
print thelp.helpcnt()
This is the documentation for the absolute core of tyler.
| Tyler |
|---|
| - |
| +chanmembers |
| +networkchan |
| +networkpass |
| +botnick |
| +botuser |
| +botnspass |
| +decloakonjoin |
| +cmdprefix |
| +opts |
| +runtime |
| +invitejoin |
| +kickrejoin |
| +version |
| - |
| +sendauth |
| +addmember |
| +changenick |
| +remmember |
| +destroymember |
| +addchan |
| +remchan |
| +abouttyler |
| +whereisUser |
| +getuptimestr |
| +dohooks |
| +doctcp |
| +docmd |
| +domsg |
| +doline |
| +recvloop |
| +dumpVisible |
You heard right! You can write tyler modules in Perl! The methodology for this is slightly different than writing tyler modules in python. For instance, with the Perl tyler-modules, you have no need to "Hook" functions and events, instead, you simply create a subroutine handler for that event. tmodperl hooks all the trod events and then searchs for a perl subroutine to handle it.
Due to this, the name of your subroutines are important. To create a hook handler, you must use the following naming convention:
sub MyModuleName_EventToHook {}
Where MyModuleName MUST be the name of your perl module and EventToHook is the event name you want to handle. A list of the hookable events is given above. Arguements are given to the subroutine in the same fashion as the python modules,
So lets say we wanted to add a hook to all docmd events. This is our example routine in our test.pl module:
sub test_docmd {
# get the args
my @args = shift;
my $env = shift;
print "THE COMMAND WAS: " . $args[0]{"cmd"} . "\n";
0;
}
You'll have to forgive the horrible Perl, I'm by no means a qualified Perl coder
Unfortunately at time of writing, tmodperl has no way to unload/load or reload perl modules on the fly, unlike the python modules which are loading dynamically when needed. This means that the hook event unload does not exist for perl modules. In addition the parameters supplied to the load hook are difference, in that not only does it provide the modulename of the perl tyler-module, but it also provides references to various core tyler modules. See below for full breakdown of args.
Hook Event: load.
Called: when the perl tyler-module is loaded into tmodperl