| mira | ||
| tests | ||
| .gitignore | ||
| LICENSE | ||
| README.md | ||
| setup.py | ||
mira
mira is a command-based bot framework for XMPP. It allows you to create bots that react to your users' commands or notify them based on a subscribtion system.
Configuration
The main bot configuration is based on a TOML file:
# The JID to authenticate as
jid = "awesome-bot@example.org"
# The password
password = "s3cr3t_p4ssw0rd"
# Where the persistent data should be stored.
# Defaults to /etc/mira/storage.json
storage_path = "/home/mira/storage.json"
# Loads the file as an avatar and publishes it (OPTIONAL)
avatar = "/etc/mira/avatar.png"
# A list of modules that should be loaded
[[modules]]
# Load the "test" module that greets a user to writes
# "test" to awesome-bot@example.org
name = "mira.modules.test"
greeting = "Hello, Mr. %%user%%!"
[[modules]]
# This module reacts only to users whose JID has the
# same domain as the bot
name = "mira.modules.other_test"
restrict_local = true
By default, mira expects the config at /etc/mira/config.toml, but the path
can be overwritten by passing --config.
Writing a module
Writing a module is pretty easy. The following is the base template:
from mira.module import BaseModule
NAME = 'new'
class NewModule(BaseModule):
__instance = None
@staticmethod
def get_instance(base, **kwargs):
if NewModule.__instance == None:
NewModule(base, **kwargs)
return NewModule.__instance
def __init__(self, base, **kwargs):
if NewModule.__instance != None:
raise Exception('Trying to init singleton twice')
super().__init__(base, **kwargs)
NewModule.__instance = self
async def on_command(self, cmd, msg):
# ...
pass
def get_instance(base, **kwargs):
return TestModule.get_instance(base, **kwargs)
Currently, modules are implemented as singletons, so most of the code
is just for turning the class into a singleton. What's required is the
toplevel constant NAME! It is the name of the module as the same time
the "command". mira will pass all messages that start with the value of
NAME to the on_command function. It's parameters are the message body
whitespace separated (cmd) and the original aioxmpp message object (msg).
If you want to add configuration options to your bot, you can use the module's
get_option(key, default=None) function, which works exactly like dict.get(...).
If you have subcommands, like "new something1" and "new something2", then you can use a subcommand table. It is just a dictionary that tells mira which function to call on which subcommand. In the example above, it looks like this:
from mira.module import BaseModule
NAME = 'new'
class NewModule(BaseModule):
__instance = None
@staticmethod
def get_instance(base, **kwargs):
if NewModule.__instance == None:
NewModule(base, **kwargs)
return NewModule.__instance
def __init__(self, base, **kwargs):
if NewModule.__instance != None:
raise Exception('Trying to init singleton twice')
super().__init__(base, **kwargs)
NewModule.__instance = self
self._subcommand_table = {
'something1': self._something1,
'something2': self._something2,
'*': self._help
}
async def _something1(self, cmd, msg):
# ...
async def _something2(self, cmd, msg):
# ...
async def _help(self, cmd, msg):
# ...
def get_instance(base, **kwargs):
return TestModule.get_instance(base, **kwargs)
Note that '*' tells mira that the function should be called everytime no other subcommand matches.
To send a message, the simplest way is to use the module's
send_message(to, body) function, which takes an aioxmpp
JID as to and a string as body.
Storage
If your module needs to store data, then you can use the
StorageManager. It is available via the module's
_stm property. It provides the following two functions:
get_data(section): Retrieve data (dictionary) stored in the module's section. A module may have multiple sectionsset_data(section, data): Stores data (dictionary) in the module's section. A module may have multiple sections
Subscriptions
If your users should be able to subscribe to certain events, then you can use the
SubscriptionManager, available via the module's _sum property. It exposes a lot more
functions, so it is probably the better to just look at it's code at mira/subscription.py.
Examples
If the test module mira.modules.test is not advanced enough, then you can find more examples here:
License
See LICENSE.