diff --git a/disco/util/runner.py b/disco/util/runner.py new file mode 100644 index 0000000..6c9c93f --- /dev/null +++ b/disco/util/runner.py @@ -0,0 +1,68 @@ +""" Utility module to help run a bot programmatically. """ +from __future__ import absolute_import +import logging +from gevent import monkey + +monkey.patch_all() + +try: + from typing import Any, Union +except ImportError: + # just give up on typing... + Any = None + Union = None + +# imports from disco (if moved to the top, they will probably break +# due to requiring `gevent`'s monkey patching for asynchronous) +from disco.client import Client, ClientConfig # noqa: E402 +from disco.bot import Bot, BotConfig # noqa: E402 +from disco.util.logging import setup_logging # noqa: E402 +from disco.gateway.sharder import AutoSharder # noqa: E402 + + +def bot_creator(config=None, bot=True, autosharded=False, **kwargs): + # type: (dict, bool, bool, **Any) -> Union[Bot, Client, AutoSharder] + """ + Create a bot object and return it to be run without the cli. + + Parameters + ----------- + config : dict + The configuration to use. The configuration can also be passed through using + keyword args, for example: `bot_creator({'bot':{'commands_prefix':'!'}}, token=TOKEN)` + bot : bool + Whether to return a :class:`disco.bot.bot.Bot` or a :class:`disco.client.Client` + `True` for `Bot`, `False` for `Client`. This only matters if the config has no `bot` key. + autosharded : bool + Whether to automatically shard the bot. + + Yields + ------- + :class:`disco.bot.bot.Bot` or :class:`disco.gateway.sharder.AutoSharder` or :class:`disco.client.Client` + A bot with all the configuration specified. + """ + config = config or {} + config.update(kwargs) + + # Change the dictionary configuration to disco's proprietary Config + config = ClientConfig(config) + + # Magical auto-sharding that you will eventually want + if autosharded: + return AutoSharder(config) + + # Setup logging based on the configured level + setup_logging(level=getattr(logging, config.log_level.upper())) + + # Create the bot/client + client = Client(config) + + # if there exists a config for the bot, then return the bot, else return the client. + if hasattr(config, 'bot'): + bot_config = BotConfig(config.bot) + return Bot(client, bot_config) + elif bot: + bot_config = BotConfig() + return Bot(client, bot_config) + else: + return client diff --git a/docs/bot_tutorial/programmatic_running.md b/docs/bot_tutorial/programmatic_running.md new file mode 100644 index 0000000..dc624ce --- /dev/null +++ b/docs/bot_tutorial/programmatic_running.md @@ -0,0 +1,58 @@ +# CLI-less Running + +In certain environments, it is either impossible +to get to a console, or completely impractical. +Even if you are not using said environments, being +able to start your bot in a python file is very +useful for config options that require functions. + +Disco has the `util.runner` module just for this task. Just simply: +```py +from disco.util import runner + +bot = runner.bot_creator({ + 'token': 'YOUR.TOKEN.HERE', + 'bot': { + 'plugins': ['plugins.tutorial']} # this can be anything +}) + +bot.run_forever() +``` + +Now you just need to `python main.py`, and the bot starts! Nice! + +### Custom prefixes + +One of the main reasons why you may want to use this method of +starting your bot is that now you can give functions for configuration. +That is especially useful if, for example, you really want server-specific +prefixes, or prefixes based on the user. All you need to do is put +a function which takes the message object and returns an array of strings. + +For example, this bot will have different prefixes for the owner vs +a random user: +```py +from disco.util import runner + +TOKEN = 'YOUR_TOKEN_HERE' +OWNER_ID = 'YOUR_USER_ID_HERE' + + +def prefix_getter(message): + if str(message.author.id) == OWNER_ID: + return ['@'] + else: + return ['!'] + + +bot = runner.bot_creator({ + 'token': TOKEN, + 'bot': { + 'commands_prefix_getter': prefix_getter, + 'require_mention': False, + 'plugins': ['plugins.tutorial'] # this can be anything + } +}) + +bot.run_forever() +``` \ No newline at end of file