-
Notifications
You must be signed in to change notification settings - Fork 0
plugin dev
- Tips before you get started
- Writing a simple plugin
- [imports for versions [<v1.6.x]] (#deprecation)
- Sending a message asynchronously while computing a command
- make err split the arguments for you [v1.2.1]
- subcommands [v1.2.0]
- Version checking [v1.3.0]
- Allow the admin to configure your plugin from the chat [v1.3.0] with an improvement [v1.4.1]
- Start a poller [v1.4.0]
- Implementing a callback to listen to every messages in the chatrooms
- Serve HTML from your plugin with xhtml-im templating [v1.5.1]
- Webhooks [v1.6.0]
Make a directory to host your new plugin or plugins and set it in config.py
BOT_EXTRA_PLUGIN_DIR = '/home/path/to/plugin/root'
You can start the bot with the "-t" command line parameter. It runs the bot in test mode, a kind of single user mode on pure console (no XMPP server involved here).
It will prompt you :
# err.py -t
[...]
INFO:Plugin activation done.
Talk to me >> _
Then you can enter all the available commands and it will trust you as an admin. Combine it with the debug mode of an IDE and you have a super snappy environment to try out and debug your code.
We've written a minimal plugin which shows the basic layout of a simple plugin. Save yourself some time by using this template as a starting point.
Let say you want to make an helloWorld plugin. First define a class implementing BotPlugin with a method decorated by @botcmd as follow :
helloWorld.py
from errbot import BotPlugin, botcmd # Note: if you use a version < 1.6.0 see below.
class HelloWorld(BotPlugin):
@botcmd # this tag this method as a command
def hello(self, mess, args): # it will respond to !hello
""" this command says hello """ # this will be the answer of !help hello
return 'Hello World !' # the bot will answer that
Then you need to put some metadescription in a .plug file.
helloWorld.plug
[Core]
Name = HelloWorld
Module = helloWorld
[Documentation]
Description = let's say hello !
Start the bot or restart it if it is already live with the command !restart.
Note : Module must match the name of the python module your main class is
That's it ! You can check if the plugin correctly load with the !status command. Then you can check if the hello command is correctly bound with !help. Then you can try it : !hello
If something goes wrong to can inspect the last lines of the log instantly with !log tail
For v1.0.0 to v1.5.1:
from errbot.botplugin import BotPlugin
from errbot.jabberbot import botcmd
Actually those still work under 1.6.x but they will generate a deprecation warning.
Often, with commands that takes long, you want to be able to send some feedback to the user that the command is progressing. You can use the helper send to achieve that.
plugin_example.py
from errbot import BotPlugin, botcmd
class PluginExample(BotPlugin):
@botcmd
def longcompute(self, mess, args):
self.send(mess.getFrom(), "/me is computing ... ", message_type=mess.getType())
[...] # long processing
return "Done !"
With the split_args_with argument to botcmd, you can specify a delimiter of the arguments and it will give you an array of strings instead of a string
@botcmd(split_args_with=' ')
def action(self, mess, args):
# if you send it !action one two three
# args will be ['one', 'two', 'three']
If you put an _ in the name of the function, err will create for you a subcommand. It is useful to categorize a feature
@botcmd
def basket_add(self, mess, args):
# it will respond to !basket add
def basket_remove(self, mess, args):
# it will respond to !basket remove
Note: for backward compatibility it will also answer to !basket_add and !basket_remove
You can enforce a minimal and maximal version of err if you know that your plugin won't be compatible outside the range. You just have to define min_err_version and/or max_err_version as a property or field. Note: the version is inclusive. It MUST be defined as a string with 3 numbers dotted like '1.3.0'
plugin_example.py
from errbot import BotPlugin
class PluginExample(BotPlugin):
min_err_version = '1.2.2'
[...]
Err can keep a simple python object for the configuration of your plugin. I avoids asking for the admin to edit config.py, restart the bot...
In order to enable this feature, you need to give a configuration template (ie. a config example) by overriding the get_configuration_template method, for example a plugin requesting a dictionary with 2 entries in there.
plugin_example.py
from errbot import BotPlugin
class PluginExample(BotPlugin):
def get_configuration_template(self):
return {'ID_TOKEN' : '00112233445566778899aabbccddeeff', 'USERNAME':'changeme'}
This is the minimal implementation.
Then from the admin you will be able to request the default template with !config PluginExample. Then it will instruct you to do a !config PluginExample {'ID_TOKEN' : '00112233445566778899aabbccddeeff', 'USERNAME':'changeme'} with the real values in there.
You will be able to recall the config set with again: !config PluginExample
From within your code, your config will be in self.config
@botcmd
def mycommand(self, mess, args):
# oh I need my TOKEN !
token = self.config['ID_TOKEN'] # <- Note: this is already a real python dict here
[new in v1.4.1]
Now the framework will do be default a strict check on structure and types or the config : by default it will do only a BASIC check. You need to override it if you want to do more complex checks. it will be called before the configure callback. Note if the config_template is None, it will never be called
It means recusively:
- in case of a dictionary, it will check if all the entries and from the same type are there and not more
- in case of an array or tuple, it will assume array members of the same type of first element of the template (no mix typed is supported)
If you need a more complex validation you need to override check_configuration :
def check_configuration(self, configuration):
# ... and here check the configuration as in v1.3.0 for the configure (see below)
# if you encounter a validation error you need to throw a errbot.util.ValidationException).
[otherwise if you are still on v1.3.0 you need to do that....]
But be careful, you might want to be more defensive towards the user input to be sure the plugin will run with it. For that, override the method configure. Note: if you have no configuration set yet, it will pass you None as parameter, you code has to take care of this case. Note 2: Don't forget to call super otherwise the framework will not store it.
For example :
plugin_example.py
from errbot import BotPlugin
class PluginExample(BotPlugin):
def configure(self, configuration):
if configuration: # if it is not configured ignore
if type(configuration) != dict:
raise Exception('Wrong configuration type')
if not configuration.has_key('ID_TOKEN') or not configuration.has_key('USERNAME'):
raise Exception('Wrong configuration type, it should contain ID_TOKEN and USERNAME')
if len(configuration) > 2:
raise Exception('What else did you try to insert in my config ?')
super(PluginExample, self).configure(configuration)
You can add a specific callback that will be called on any message sent on the chatroom. It is useful to react at specific keywords even the the bot is not called explicitely with the ! commands.
plugin_example.py
from errbot import BotPlugin
class PluginExample(BotPlugin):
def callback_message(self, conn, mess):
if mess.getBody().find('cookie') != -1:
self.send(mess.getFrom(), "What what somebody said cookie !?", message_type=mess.getType())
Note: Up to and including version 1.6.7, Err suffered from a bug where this could cause an infinite loop when called from within a MUC
Simply register your polling function at activation time:
plugin_example.py
from errbot import BotPlugin
import logging
class PluginExample(BotPlugin):
def my_callback(self):
logging.debug('I am called every minute')
def activate(self):
super(PluginExample, self).activate()
self.start_poller(60, self.my_callback)
This is the simplest case. See Botplugin for added parameters, starting several pollers, stopping pollers etc ...