2019-12-16 15:38:35 -09:00

153 lines
5.8 KiB
Python

import os
import json
from concurrent import futures
from multiprocessing import Pool
import logging
import discord
from discord.ext import commands
from discord.ext.commands.context import Context
from geeksbot.imports.strings import MyStringView
import redis
import aiohttp
geeksbot_logger = logging.getLogger('Geeksbot')
class Geeksbot(commands.Bot):
def __init__(self, *args, **kwargs):
self.default_prefix = os.environ.get('DISCORD_DEFAULT_PREFIX', 'g$')
kwargs['command_prefix'] = self.get_prefixes
self.description = "Geeksbot v2"
kwargs['description'] = self.description
super().__init__(*args, **kwargs)
self.config_dir = 'geeksbot/config'
self.config_file = 'bot_config.json'
self.extension_dir = 'exts'
self.cache = redis.Redis(host=os.environ['REDIS_HOST'], port=os.environ['REDIS_PORT'], db=1, charset="utf-8", decode_responses=True)
self.api_token = os.environ['API_TOKEN']
self.aio_session = aiohttp.ClientSession(loop=self.loop)
self.auth_header = {'Authorization': f'Token {self.api_token}'}
self.api_base = 'https://geeksbot.app/api'
with open(f'{self.config_dir}/{self.config_file}') as f:
self.bot_config = json.load(f)
self.embed_color = discord.Colour.from_rgb(49, 107, 111)
self.error_color = discord.Colour.from_rgb(142, 29, 31)
self.tpe = futures.ThreadPoolExecutor(max_workers=20)
self.process_pool = Pool(processes=4)
self.geo_api = '2d4e419c2be04c8abe91cb5dd1548c72'
self.git_url = 'https://github.com/dustinpianalto/geeksbot_v2'
self.load_default_extensions()
self.owner_id = 351794468870946827
self.book_emojis = {
'unlock': '🔓',
'start': '',
'back': '',
'hash': '#\N{COMBINING ENCLOSING KEYCAP}',
'forward': '',
'end': '',
'close': '🇽',
}
async def load_ext(self, mod):
try:
self.load_extension(f'geeksbot.{self.extension_dir}.{mod}')
geeksbot_logger.info(f'Extension Loaded: {mod}')
except Exception:
geeksbot_logger.exception(f"Error loading {mod}")
async def unload_ext(self, mod):
try:
self.unload_extension(f'geeksbot.{self.extension_dir}.{mod}')
geeksbot_logger.info(f'Extension Unloaded: {mod}')
except Exception:
geeksbot_logger.exception(f"Error loading {mod}")
def load_default_extensions(self):
for load_item in self.bot_config['load_list']:
self.loop.create_task(self.load_ext(load_item))
async def get_prefixes(self, bot, message):
return self.default_prefix.casefold()
async def get_context(self, message, *, cls=Context):
r"""|coro|
Returns the invocation context from the message.
This is a more low-level counter-part for :meth:`.process_commands`
to allow users more fine grained control over the processing.
The returned context is not guaranteed to be a valid invocation
context, :attr:`.Context.valid` must be checked to make sure it is.
If the context is not valid then it is not a valid candidate to be
invoked under :meth:`~.Bot.invoke`.
Parameters
-----------
message: :class:`discord.Message`
The message to get the invocation context from.
cls
The factory class that will be used to create the context.
By default, this is :class:`.Context`. Should a custom
class be provided, it must be similar enough to :class:`.Context`\'s
interface.
Returns
--------
:class:`.Context`
The invocation context. The type of this can change via the
``cls`` parameter.
"""
view = MyStringView(message.content)
ctx = cls(prefix=None, view=view, bot=self, message=message)
if self._skip_check(message.author.id, self.user.id):
return ctx
prefix = await self.get_prefix(message)
invoked_prefix = prefix
if isinstance(prefix, str):
if not view.skip_string(prefix):
return ctx
else:
try:
# if the context class' __init__ consumes something from the view this
# will be wrong. That seems unreasonable though.
if message.content.casefold().startswith(tuple(prefix)):
invoked_prefix = discord.utils.find(view.skip_string, prefix)
else:
return ctx
except TypeError:
if not isinstance(prefix, list):
raise TypeError("get_prefix must return either a string or a list of string, "
"not {}".format(prefix.__class__.__name__))
# It's possible a bad command_prefix got us here.
for value in prefix:
if not isinstance(value, str):
raise TypeError("Iterable command_prefix or list returned from get_prefix must "
"contain only strings, not {}".format(value.__class__.__name__))
# Getting here shouldn't happen
raise
invoker = view.get_word()
ctx.invoked_with = invoker
ctx.prefix = invoked_prefix
ctx.command = self.all_commands.get(invoker)
return ctx
async def close(self):
try:
await super().close()
await self.aio_session.close()
except Exception:
geeksbot_logger.exception(f"Error Closing Connections.")
geeksbot_logger.info('Exiting...')