11import asyncio
22import socket
3+ from typing import Optional
34
5+ import aiohttp
46import discord
57from discord import Embed
68from discord .ext import commands
@@ -19,13 +21,14 @@ def __init__(self, **kwargs):
1921 super ().__init__ (** kwargs )
2022 self ._guild_available = asyncio .Event ()
2123
22- statsd_url = constants .Stats .statsd_host
24+ self .http_session : Optional [aiohttp .ClientSession ] = None
25+ self ._connector : Optional [aiohttp .TCPConnector ] = None
26+ self ._resolver : Optional [aiohttp .AsyncResolver ] = None
2327
24- if constants .DEBUG_MODE :
25- # Since statsd is UDP, there are no errors for sending to a down port.
26- # For this reason, setting the statsd host to 127.0.0.1 for development
27- # will effectively disable stats.
28- statsd_url = LOCALHOST
28+ # Since statsd is UDP, there are no errors for sending to a down port.
29+ # For this reason, setting the statsd host to 127.0.0.1 for development
30+ # will effectively disable stats.
31+ statsd_url = LOCALHOST if constants .DEBUG_MODE else constants .Stats .statsd_host
2932
3033 self ._statsd_timerhandle : asyncio .TimerHandle = None
3134 self .stats = async_stats .AsyncStatsClient (self .loop , LOCALHOST )
@@ -161,6 +164,15 @@ async def close(self) -> None:
161164
162165 await super ().close ()
163166
167+ if self .http_session :
168+ await self .http_session .close ()
169+
170+ if self ._connector :
171+ await self ._connector .close ()
172+
173+ if self ._resolver :
174+ await self ._resolver .close ()
175+
164176 if self .stats ._transport :
165177 self .stats ._transport .close ()
166178
@@ -169,5 +181,21 @@ async def close(self) -> None:
169181
170182 async def login (self , * args , ** kwargs ) -> None :
171183 """Re-create the stats socket before logging into Discord."""
184+ # Use asyncio for DNS resolution instead of threads so threads aren't spammed.
185+ self ._resolver = aiohttp .AsyncResolver ()
186+
187+ # Use AF_INET as its socket family to prevent HTTPS related problems both locally
188+ # and in production.
189+ self ._connector = aiohttp .TCPConnector (
190+ resolver = self ._resolver ,
191+ family = socket .AF_INET ,
192+ )
193+
194+ # Client.login() will call HTTPClient.static_login() which will create a session using
195+ # this connector attribute.
196+ self .http .connector = self ._connector
197+
198+ self .http_session = aiohttp .ClientSession (connector = self ._connector )
199+
172200 await self .stats .create_socket ()
173201 await super ().login (* args , ** kwargs )
0 commit comments