Example #1
0
File: bot.py Project: Red-M/Stratus
    def __init__(self, loop=asyncio.get_event_loop()):
        # basic variables
        self.loop = loop
        self.start_time = time.time()
        self.running = True
        # future which will be called when the bot stops
        self.stopped_future = asyncio.Future(loop=self.loop)

        # stores each bot server connection
        self.connections = []

        # set up config
        self.config = Config(self)
        logger.debug("Config system initialised.")

        # setup db
        db_config = self.config.get('database')
        db_host = db_config.get('host', 'localhost')
        db_port = db_config.get('port', 6379)
        db_database = db_config.get('database', 0)
        logger.info("Connecting to redis at {}:{}/{}".format(db_host, db_port, db_database))
        self.db = redis.StrictRedis(host=db_host, port=db_port, db=db_database)
        logger.debug("Database system initialised.")

        # Bot initialisation complete
        logger.debug("Bot setup completed.")

        # create bot connections
        self.create_connections()

        self.plugin_manager = PluginManager(self)
Example #2
0
File: bot.py Project: Red-M/Stratus
class ObrBot:
    """
    :type start_time: float
    :type running: bool
    :type connections: list[Connection | IrcConnection]
    :type config: core.config.Config
    :type plugin_manager: PluginManager
    :type db: redis.StrictRedis
    :type loop: asyncio.events.AbstractEventLoop
    :type stopped_future: asyncio.Future
    :param: stopped_future: Future that will be given a result when the bot has stopped.
    """

    def __init__(self, loop=asyncio.get_event_loop()):
        # basic variables
        self.loop = loop
        self.start_time = time.time()
        self.running = True
        # future which will be called when the bot stops
        self.stopped_future = asyncio.Future(loop=self.loop)

        # stores each bot server connection
        self.connections = []

        # set up config
        self.config = Config(self)
        logger.debug("Config system initialised.")

        # setup db
        db_config = self.config.get('database')
        db_host = db_config.get('host', 'localhost')
        db_port = db_config.get('port', 6379)
        db_database = db_config.get('database', 0)
        logger.info("Connecting to redis at {}:{}/{}".format(db_host, db_port, db_database))
        self.db = redis.StrictRedis(host=db_host, port=db_port, db=db_database)
        logger.debug("Database system initialised.")

        # Bot initialisation complete
        logger.debug("Bot setup completed.")

        # create bot connections
        self.create_connections()

        self.plugin_manager = PluginManager(self)

    def run(self):
        """
        Starts ObrBot.
        This will load plugins, connect to IRC, and process input.
        :return: True if ObrBot should be restarted, False otherwise
        :rtype: bool
        """
        # Initializes the bot, plugins and connections
        self.loop.run_until_complete(self._init_routine())
        # Wait till the bot stops. The stopped_future will be set to True to restart, False otherwise
        restart = self.loop.run_until_complete(self.stopped_future)
        self.loop.close()
        return restart

    def create_connections(self):
        """ Create a BotConnection for all the networks defined in the config """
        for config in self.config['connections']:
            # strip all spaces and capitalization from the connection name
            name = clean_name(config['name'])
            nick = config['nick']
            server = config['connection']['server']
            port = config['connection'].get('port', 6667)

            self.connections.append(IrcConnection(self, name, nick, config=config,
                                                  server=server, port=port,
                                                  use_ssl=config['connection'].get('ssl', False)))
            logger.debug("[{}] Created connection.".format(name))

    @asyncio.coroutine
    def stop(self, reason=None, *, restart=False):
        """quits all networks and shuts the bot down"""
        logger.info("Stopping.")

        for connection in self.connections:
            if not connection.connected:
                # Don't quit a connection that hasn't connected
                continue
            logger.debug("[{}] Closing connection.".format(connection.name))

            connection.quit(reason)

        yield from asyncio.sleep(0.5)  # wait for 'QUIT' calls to take affect

        for connection in self.connections:
            if not connection.connected:
                # Don't close a connection that hasn't connected
                continue
            connection.close()

        yield from self.plugin_manager.run_shutdown_hooks()

        self.running = False
        # Give the stopped_future a result, so that run() will exit
        self.stopped_future.set_result(restart)

    @asyncio.coroutine
    def restart(self, reason=None):
        """shuts the bot down and restarts it"""
        yield from self.stop(reason=reason, restart=True)

    @asyncio.coroutine
    def _init_routine(self):
        # Load plugins
        yield from self.plugin_manager.load_all(self.config.get("plugin_directories", ["plugins"]))

        # If we we're stopped while loading plugins, cancel that and just stop
        if not self.running:
            logger.info("Killed while loading, exiting")
            return

        # Connect to servers
        yield from asyncio.gather(*[conn.connect() for conn in self.connections], loop=self.loop)

        # Run a manual garbage collection cycle, to clean up any unused objects created during initialization
        gc.collect()

    @asyncio.coroutine
    def process(self, event):
        """
        :type event: Event
        """
        first = []
        tasks = []
        command_prefix = event.conn.config.get('command_prefix', '.')

        if hasattr(event, 'irc_command'):
            # Raw IRC hook
            for raw_hook in self.plugin_manager.catch_all_triggers:
                if raw_hook.run_first:
                    first.append(self.plugin_manager.launch(raw_hook, event))
                else:
                    tasks.append(self.plugin_manager.launch(raw_hook, event))
            if event.irc_command in self.plugin_manager.raw_triggers:
                for raw_hook in self.plugin_manager.raw_triggers[event.irc_command]:
                    if raw_hook.run_first:
                        first.append(self.plugin_manager.launch(raw_hook, event))
                    else:
                        tasks.append(self.plugin_manager.launch(raw_hook, event))

        # Event hooks
        if event.type in self.plugin_manager.event_type_hooks:
            for event_hook in self.plugin_manager.event_type_hooks[event.type]:
                if event_hook.run_first:
                    first.append(self.plugin_manager.launch(event_hook, event))
                else:
                    tasks.append(self.plugin_manager.launch(event_hook, event))

        if event.type is EventType.message:
            # Commands
            if event.chan_name.lower() == event.nick.lower():  # private message, no command prefix
                command_re = r'(?i)^(?:[{}]?|{}[,;:]+\s+)([\w-]+)(?:$|\s+)(.*)'.format(command_prefix,
                                                                                       event.conn.bot_nick)
            else:
                command_re = r'(?i)^(?:[{}]|{}[,;:]+\s+)([\w-]+)(?:$|\s+)(.*)'.format(command_prefix,
                                                                                      event.conn.bot_nick)

            match = re.match(command_re, event.content)

            if match:
                command = match.group(1).lower()
                if command in self.plugin_manager.commands:
                    command_hook = self.plugin_manager.commands[command]
                    command_event = CommandHookEvent(hook=command_hook, text=match.group(2).strip(),
                                                     triggered_command=command, base_event=event)
                    if command_hook.run_first:
                        first.append(self.plugin_manager.launch(command_hook, event, command_event))
                    else:
                        tasks.append(self.plugin_manager.launch(command_hook, event, command_event))

            # Regex hooks
            for regex, regex_hook in self.plugin_manager.regex_hooks:
                match = regex.search(event.content)
                if match:
                    regex_event = RegexHookEvent(hook=regex_hook, match=match, base_event=event)
                    if regex_hook.run_first:
                        first.append(self.plugin_manager.launch(regex_hook, event, regex_event))
                    else:
                        tasks.append(self.plugin_manager.launch(regex_hook, event, regex_event))

        # Run the tasks
        yield from asyncio.gather(*first, loop=self.loop)
        yield from asyncio.gather(*tasks, loop=self.loop)