forked from notnotmelon/skyblock-simplified
-
Notifications
You must be signed in to change notification settings - Fork 1
/
bot.py
111 lines (89 loc) · 3.78 KB
/
bot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import sys
import traceback
import discord
import aiohttp
import socket
from typing import Optional
from discord.ext import commands
from lib import HypixelAPIClient
from utils import Context
import config
class Bot(commands.AutoShardedBot):
def __init__(self, *args, **kwargs):
if "connector" in kwargs:
print(
"If login() is called (or the bot is started), the connector will be overwritten with an internal one")
super().__init__(*args, **kwargs)
self.config = config
self.http_session: Optional[aiohttp.ClientSession] = None
self.hypixel_api_client = HypixelAPIClient(config.API_KEY, self.loop, timeout=aiohttp.ClientTimeout(total=30))
self._connector = None
self._resolver = None
async def process_commands(self, message):
if message.author.bot:
return
ctx = await self.get_context(message, cls=Context)
if self.user.mentioned_in(ctx.message) and len(ctx.message.content.split()) == 1:
await ctx.send_help() # Send help if bot get ping
else:
await self.invoke(ctx)
async def on_message(self, message):
if message.author.bot or not self.is_ready():
return
await self.process_commands(message)
async def on_error(self, event_method, *args, **kwargs):
type_, value_, traceback_ = sys.exc_info()
if isinstance(value_, discord.errors.Forbidden):
# in case it raised from on_command_error
return
error = traceback.format_exc().replace('```', '"""')
for dev_id in self.config.DEV_IDS:
await self.get_user(dev_id).send(f'```{error[-1950:]}```')
print(error)
def add_cog(self, cog: commands.Cog):
super().add_cog(cog)
print(f"Cog loaded: {type(cog).__name__} ({cog.qualified_name}).")
def clear(self):
"""
Clears the internal state of the bot and recreates the connector and sessions.
Will cause a DeprecationWarning if called outside a coroutine.
"""
self._recreate()
super().clear()
async def close(self):
"""
Close the Discord connection, the http session, connector, resolver and hypixel api client.
"""
await super().close()
await self.hypixel_api_client.close()
if self._connector:
await self._connector.close()
if self._resolver:
await self._resolver.close()
if self.http_session:
await self.http_session.close()
async def login(self, *args, **kwargs):
"""
Re-create the connector and set up sessions before logging into Discord.
"""
self._recreate()
await super().login(*args, **kwargs)
# noinspection PyProtectedMember
def _recreate(self):
"""
Re-create the connector, aiohttp session and the APIClient.
"""
# Use asyncio for DNS resolution instead of threads so threads aren't spammed.
self._resolver = aiohttp.AsyncResolver()
if self._connector and not self._connector._closed:
print("The previous connector was not closed; it will remain open and be overwritten")
if self.http_session and not self.http_session.closed:
print('The previous http session was not closed, it will remain open and be overwritten')
self._connector = aiohttp.TCPConnector(
resolver=self._resolver,
family=socket.AF_INET,
)
self.http.connector = self._connector
self.http_session = aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=30), connector=self._connector,
raise_for_status=True)
self.hypixel_api_client.recreate(force=True, connector=self._connector)