mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-07-09 11:31:58 +00:00
Fix type errors and potentially unbound code in http.py
This commit is contained in:
parent
4152819a3c
commit
7d9074db8a
@ -42,6 +42,7 @@ from typing import (
|
|||||||
Tuple,
|
Tuple,
|
||||||
Type,
|
Type,
|
||||||
TypeVar,
|
TypeVar,
|
||||||
|
Union,
|
||||||
)
|
)
|
||||||
from urllib.parse import quote as _uriquote
|
from urllib.parse import quote as _uriquote
|
||||||
import weakref
|
import weakref
|
||||||
@ -51,6 +52,7 @@ import aiohttp
|
|||||||
from .errors import HTTPException, Forbidden, NotFound, LoginFailure, DiscordServerError, GatewayNotFound
|
from .errors import HTTPException, Forbidden, NotFound, LoginFailure, DiscordServerError, GatewayNotFound
|
||||||
from .gateway import DiscordClientWebSocketResponse
|
from .gateway import DiscordClientWebSocketResponse
|
||||||
from . import __version__, utils
|
from . import __version__, utils
|
||||||
|
from .utils import MISSING
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -93,7 +95,7 @@ if TYPE_CHECKING:
|
|||||||
Response = Coroutine[Any, Any, T]
|
Response = Coroutine[Any, Any, T]
|
||||||
|
|
||||||
|
|
||||||
async def json_or_text(response: aiohttp.ClientResponse) -> Any:
|
async def json_or_text(response: aiohttp.ClientResponse) -> Union[Dict[str, Any], str]:
|
||||||
text = await response.text(encoding='utf-8')
|
text = await response.text(encoding='utf-8')
|
||||||
try:
|
try:
|
||||||
if response.headers['content-type'] == 'application/json':
|
if response.headers['content-type'] == 'application/json':
|
||||||
@ -170,7 +172,7 @@ class HTTPClient:
|
|||||||
) -> None:
|
) -> None:
|
||||||
self.loop: asyncio.AbstractEventLoop = asyncio.get_event_loop() if loop is None else loop
|
self.loop: asyncio.AbstractEventLoop = asyncio.get_event_loop() if loop is None else loop
|
||||||
self.connector = connector
|
self.connector = connector
|
||||||
self.__session: Optional[aiohttp.ClientSession] = None # filled in static_login
|
self.__session: aiohttp.ClientSession = MISSING # filled in static_login
|
||||||
self._locks: weakref.WeakValueDictionary = weakref.WeakValueDictionary()
|
self._locks: weakref.WeakValueDictionary = weakref.WeakValueDictionary()
|
||||||
self._global_over: asyncio.Event = asyncio.Event()
|
self._global_over: asyncio.Event = asyncio.Event()
|
||||||
self._global_over.set()
|
self._global_over.set()
|
||||||
@ -223,7 +225,7 @@ class HTTPClient:
|
|||||||
self._locks[bucket] = lock
|
self._locks[bucket] = lock
|
||||||
|
|
||||||
# header creation
|
# header creation
|
||||||
headers = {
|
headers: Dict[str, str] = {
|
||||||
'User-Agent': self.user_agent,
|
'User-Agent': self.user_agent,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,6 +256,8 @@ class HTTPClient:
|
|||||||
# wait until the global lock is complete
|
# wait until the global lock is complete
|
||||||
await self._global_over.wait()
|
await self._global_over.wait()
|
||||||
|
|
||||||
|
response: Optional[aiohttp.ClientResponse] = None
|
||||||
|
data: Optional[Union[Dict[str, Any], str]] = None
|
||||||
await lock.acquire()
|
await lock.acquire()
|
||||||
with MaybeUnlock(lock) as maybe_lock:
|
with MaybeUnlock(lock) as maybe_lock:
|
||||||
for tries in range(5):
|
for tries in range(5):
|
||||||
@ -268,36 +272,36 @@ class HTTPClient:
|
|||||||
kwargs['data'] = form_data
|
kwargs['data'] = form_data
|
||||||
|
|
||||||
try:
|
try:
|
||||||
async with self.__session.request(method, url, **kwargs) as r:
|
async with self.__session.request(method, url, **kwargs) as response:
|
||||||
log.debug('%s %s with %s has returned %s', method, url, kwargs.get('data'), r.status)
|
log.debug('%s %s with %s has returned %s', method, url, kwargs.get('data'), response.status)
|
||||||
|
|
||||||
# even errors have text involved in them so this is safe to call
|
# even errors have text involved in them so this is safe to call
|
||||||
data = await json_or_text(r)
|
data = await json_or_text(response)
|
||||||
|
|
||||||
# check if we have rate limit header information
|
# check if we have rate limit header information
|
||||||
remaining = r.headers.get('X-Ratelimit-Remaining')
|
remaining = response.headers.get('X-Ratelimit-Remaining')
|
||||||
if remaining == '0' and r.status != 429:
|
if remaining == '0' and response.status != 429:
|
||||||
# we've depleted our current bucket
|
# we've depleted our current bucket
|
||||||
delta = utils._parse_ratelimit_header(r, use_clock=self.use_clock)
|
delta = utils._parse_ratelimit_header(response, use_clock=self.use_clock)
|
||||||
log.debug('A rate limit bucket has been exhausted (bucket: %s, retry: %s).', bucket, delta)
|
log.debug('A rate limit bucket has been exhausted (bucket: %s, retry: %s).', bucket, delta)
|
||||||
maybe_lock.defer()
|
maybe_lock.defer()
|
||||||
self.loop.call_later(delta, lock.release)
|
self.loop.call_later(delta, lock.release)
|
||||||
|
|
||||||
# the request was successful so just return the text/json
|
# the request was successful so just return the text/json
|
||||||
if 300 > r.status >= 200:
|
if 300 > response.status >= 200:
|
||||||
log.debug('%s %s has received %s', method, url, data)
|
log.debug('%s %s has received %s', method, url, data)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
# we are being rate limited
|
# we are being rate limited
|
||||||
if r.status == 429:
|
if response.status == 429:
|
||||||
if not r.headers.get('Via'):
|
if not response.headers.get('Via') or isinstance(data, str):
|
||||||
# Banned by Cloudflare more than likely.
|
# Banned by Cloudflare more than likely.
|
||||||
raise HTTPException(r, data)
|
raise HTTPException(response, data)
|
||||||
|
|
||||||
fmt = 'We are being rate limited. Retrying in %.2f seconds. Handled under the bucket "%s"'
|
fmt = 'We are being rate limited. Retrying in %.2f seconds. Handled under the bucket "%s"'
|
||||||
|
|
||||||
# sleep a bit
|
# sleep a bit
|
||||||
retry_after: float = data['retry_after'] # type: ignore
|
retry_after: float = data['retry_after']
|
||||||
log.warning(fmt, retry_after, bucket)
|
log.warning(fmt, retry_after, bucket)
|
||||||
|
|
||||||
# check if it's a global rate limit
|
# check if it's a global rate limit
|
||||||
@ -318,19 +322,19 @@ class HTTPClient:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# we've received a 500 or 502, unconditional retry
|
# we've received a 500 or 502, unconditional retry
|
||||||
if r.status in {500, 502}:
|
if response.status in {500, 502}:
|
||||||
await asyncio.sleep(1 + tries * 2)
|
await asyncio.sleep(1 + tries * 2)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# the usual error cases
|
# the usual error cases
|
||||||
if r.status == 403:
|
if response.status == 403:
|
||||||
raise Forbidden(r, data)
|
raise Forbidden(response, data)
|
||||||
elif r.status == 404:
|
elif response.status == 404:
|
||||||
raise NotFound(r, data)
|
raise NotFound(response, data)
|
||||||
elif r.status == 503:
|
elif response.status == 503:
|
||||||
raise DiscordServerError(r, data)
|
raise DiscordServerError(response, data)
|
||||||
else:
|
else:
|
||||||
raise HTTPException(r, data)
|
raise HTTPException(response, data)
|
||||||
|
|
||||||
# This is handling exceptions from the request
|
# This is handling exceptions from the request
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
@ -340,11 +344,14 @@ class HTTPClient:
|
|||||||
continue
|
continue
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
if response is not None:
|
||||||
# We've run out of retries, raise.
|
# We've run out of retries, raise.
|
||||||
if r.status >= 500:
|
if response.status >= 500:
|
||||||
raise DiscordServerError(r, data)
|
raise DiscordServerError(response, data)
|
||||||
|
|
||||||
raise HTTPException(r, data)
|
raise HTTPException(response, data)
|
||||||
|
|
||||||
|
raise RuntimeError('Unreachable code in HTTP handling')
|
||||||
|
|
||||||
async def get_from_cdn(self, url: str) -> bytes:
|
async def get_from_cdn(self, url: str) -> bytes:
|
||||||
async with self.__session.get(url) as resp:
|
async with self.__session.get(url) as resp:
|
||||||
@ -375,7 +382,7 @@ class HTTPClient:
|
|||||||
data = await self.request(Route('GET', '/users/@me'))
|
data = await self.request(Route('GET', '/users/@me'))
|
||||||
except HTTPException as exc:
|
except HTTPException as exc:
|
||||||
self.token = old_token
|
self.token = old_token
|
||||||
if exc.response.status == 401:
|
if exc.status == 401:
|
||||||
raise LoginFailure('Improper token has been passed.') from exc
|
raise LoginFailure('Improper token has been passed.') from exc
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@ -597,7 +604,7 @@ class HTTPClient:
|
|||||||
emoji=emoji,
|
emoji=emoji,
|
||||||
)
|
)
|
||||||
|
|
||||||
params = {
|
params: Dict[str, Any] = {
|
||||||
'limit': limit,
|
'limit': limit,
|
||||||
}
|
}
|
||||||
if after:
|
if after:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user