import logging from abc import ABC, abstractmethod from nio import RoomMessageText, MatrixRoom class ModuleCannotBeDisabled(Exception): pass class BotModule(ABC): """Abtract bot module A module derives from this class to process and interact on room messages. The subclass must be named `MatrixModule`. Just write a python file with desired command name and place it in modules. See current modules for examples. No need to register it anywhere else. Example: class MatrixModule(BotModule): async def matrix_message(self, bot, room, event): args = event.body.split() args.pop(0) # Echo what they said back await bot.send_text(room, ' '.join(args)) def help(self): return 'Echoes back what user has said' """ def __init__(self, name): self.enabled = True self.name = name self.logger = logging.getLogger("module " + self.name) def matrix_start(self, bot): """Called once on startup :param bot: a reference to the bot :type bot: Bot """ self.logger.info('Starting..') @abstractmethod async def matrix_message(self, bot, room, event): """Called when a message is sent to room starting with !module_name :param bot: a reference to the bot :type bot: Bot :param room: a matrix room message :type room: MatrixRoom :param event: a handle to the event that triggered the callback :type event: RoomMessageText """ pass def matrix_stop(self, bot): """Called once before exit :param bot: a reference to the bot :type bot: Bot """ self.logger.info('Stopping..') async def matrix_poll(self, bot, pollcount): """Called every 10 seconds :param bot: a reference to the bot :type bot: Bot :param pollcount: the actual poll count :type pollcount: int """ pass @abstractmethod def help(self): """Return one-liner help text""" return 'A cool hemppa module' def long_help(self, bot=None, room=None, event=None, args=[]): """Return longer help text Used by help module as !help modulename [args ...] bot, room, and event are passed to allow a module to give contextual help If not defined, falls back to short help """ return self.help() def get_settings(self): """Must return a dict object that can be converted to JSON and sent to server :return: a dict object that can be converted to JSON :rtype: dict """ return {'enabled': self.enabled,} def set_settings(self, data): """Load these settings. It should be the same JSON you returned in previous get_settings :param data: a dict object containing the settings read from the account :type data: dict """ if data.get('enabled') is not None: self.enabled = data['enabled'] def add_module_aliases(self, bot, args, force=False): """Add a list of aliases for this module. :param args: a list of strings by which this module can be called :type args: list :param force: override any existing aliases :type force: bool, optional """ for name in args: if bot.modules.get(name): self.logger.info(f"not aliasing {name}, it is already a module") continue prev = bot.module_aliases.get(name) if prev == self.name: continue if prev and not force: self.logger.info(f"not aliasing {name}, it is already an alias for {prev}") continue if prev: self.logger.debug(f"overriding alias {name} for {prev}") bot.module_aliases[name] = self.name def enable(self): self.enabled = True def disable(self): self.enabled = False