forked from theepicsnail/Yakr
-
Notifications
You must be signed in to change notification settings - Fork 0
amiller/Yakr
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Yakr is yet another IRC bot. This one is designed to be very thin, with the same plugability of Superbot and Superbot2. This requires the gevent package to be installed. (http://www.gevent.org/) End goals To start the bot: python Main.py To start a new plugin: python Main.py makePlugin <pluginName> this will create plugins/<pluginName>/__init__.py Empty, this needs to be present for the plugin to be loadable plugins/<pluginName>/<pluginName>.py Template plugin To debug your plugins: During the process of working on a plugin, it's useful to test a feature many times during development. To aid that record/replay exist. plugin Main.py record this will start the bot in "record" mode. Do this, then try out your plugin, once done, kill this process (ctrl-c) This will create a (or overwrite the) RECORD file. Once recorded, you will be able to replay (see next section) To reply the recorded data plugin Main.py replay this will start up a fake bot that doesn't connect to a server (keeps you from spamming, or needing to load/reload plugins) the RECORD file will be played through the bot to simulate the network data it experienced during the recording. The actions/outputs/etc.. from the plugins will be recorded into log files so that you can inspect what has happened. using pdb during your plugin is safe as well, since replay mode doesn't connect to a server, you can't ping out. replay can be done repeatedly until your plugin is working in replay mode To test your plugin: python Main.py test Same as below, except tests all loadable plugins python Main.py test <pluginName> if plugins/<pluginName>/<pluginName>Test.py exists, it is executed. ------- plugins ------- Plugins shouldn't have any global code Life of a plugin: Plugin is imported Global code runs here, you shouldn't have any global code. onStart() called plugin is now created, it'll be receiving events and what not after this This happens possibly even before the irc connection has been made, or hand shakes, etc.. onReady() called Ready is probably where you'll want to do your actual bot stuff upon loading. Ready is called once the connection is now ready for you to send commands (joins, messages, etc..) Right here is where the plugin will spend most of its life, making calls to your callbacks and what not. onStop() called before shutdown and when the plugin is being unloaded This is the reccomended way to trigger an event in your plugin: it will allow for future events to work, and it ensures a more consistant functionality across plugins. This should also allow name collision resolution !plugin1.foo !plugin2.foo @command("foo") def onCall(*args, *kwargs): args will consist of the "tokenized" chunks of strings for example: !foo bar baz would come across as onCall(["bar", "baz"]) !foo "bar baz" would come across as onCall(["bar baz"]) repeat 'test' | foo would come across as onCall(["test"]) $(repeat foo bar) would come across as onCall(["bar"]) This is because $( ) takes the output of whatever command is in it and reprocesses is so repeat foo bar outputs "foo bar" which gets reprocessed and "bar" becomes the argument kwargs remains unused at the moment, something like "foo bar=baz" for now will just be processed as onCall(["bar=baz"]) Just returning a string, will attempt to go back to wherever is most approriate If a message came from a channel, it'll be sent back to the channel If a message came from a private message, it'll be sent back to the sender If a message came from a notice, it'll be noticed back at the sender (this is against the IRC RFC, oops) If you're sending a message from where that the proper recipient can't be determined (eg, some timer based event) then a warning is logged, and the message is discarded. Message format: The same coloring syntax is used as before (extended!): {f} sets the fg color to color f {f,} same as above {,b} sets the background color to b {f,b} sets foreground to f, background to b {,,b} sets bold {,,i} sets italic {,,u} sets underline so, {1,2,biu} would result in foreground = 1, background = 2, bold, italic, and underline {} resets all attributes If a line starts with @ this will specify where to sent the message @nick @#channel If a message starts with * and ends with *, (after the optional @ director) then the message will be sent as an action. @snail *{1}pokes* will send a private message as an action, in the foreground color 1 If a message contains a newline, this creates a new message entirely, everything is reset (lines are handled disjointly) so the string "@snail *poke*\nHello there." will be parsed as: "@snail *poke*" "Hello there" so "Hello there" may end up not going to snail. e.g. if this is in response to an action in #adullm, "hello there" will goto adullam Any blank lines are ignored. the string "@snail hello\n\n\nworld" will be parsed as: "@snail hello" "" "" "world" which then gets filtered down to "@snail hello" "world" <- remember this line may not go to snail Protip: "\n@snail ".join(["", "hello", "*poke*"]) produces: "\n@snail hello\n@snail *poke*" which gets parsed as: "" "@snail hello" "@snail *poke*" which gets filtered to: "@snail hello" "@snail *poke*" This might be useful enough to warrent some helper/util method: def whatever(prefix, lines): return ("\n" + prefix + " ").join([""] + lines) Methods like tell("#adullam", "hello") action("#adullam", "hello") etc.. are just string modifiers: def tell(target, message): return "\n@" + target + " " + message def action(target, message): return "\n@" + target + " *" + message + "*" This allows for: out = tell("#adullam", "hi") out += action("snail", "poke") return out out = "\n@#adullam hi\n@snail *poke*" to actually push a message through the bot: send(formatted message) this is NOT recommended during the command function as only the returned message will be handled correctly (piped, reprocessed, etc..) if you're doing a send, you need to Stuff available to plugins Shelve string->object persistant storage Log file Logging object for your plugin Config file Basic config file parser (ConfigParser) Bot (Yakr!) Message building Msg(target, message) Action(target, message) (should Action just do the *'s then used like Msg(target, Action("pokes")) ?) I don't know if Action really needs to know about where the action is going. Color(fg=None, bg=None, attrs=None) Actions Send(formattedMessage) Join(channel) Part(channel) etc.. Scheduling functions After(timeout, callback) => eventId Every(timeout, callback) => eventId Cancel(eventId)
About
No description, website, or topics provided.
Resources
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published
Languages
- Python 100.0%