Skip to content

Commit

Permalink
update http errors to provide useful information
Browse files Browse the repository at this point in the history
  • Loading branch information
IAmTomahawkx committed Aug 16, 2023
1 parent aa5ac20 commit 9937590
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 13 deletions.
3 changes: 3 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ Master
- :func:`~twitchio.Client.event_token_expired` will now be called correctly when response is ``401 Invalid OAuth token``
- Fix reconnect loop when Twitch sends a RECONNECT via IRC websocket
- Fix :func:`~twitchio.CustomReward.edit` so it now can enable the reward

- Other Changes
- Updated the HTTPException to provide useful information when an error is raised.

- ext.eventsub
- Added websocket support via eventsub.EventSubWSClient
Expand Down
4 changes: 3 additions & 1 deletion twitchio/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,13 @@ class HTTPException(TwitchIOException):
def __init__(
self, message: str, *, reason: Optional[str] = None, status: Optional[int] = None, extra: Optional[Any] = None
):
self.message = message
self.message = f"{status}: {message}: {reason}"
self.reason = reason
self.status = status
self.extra = extra

super().__init__(self.message)


class Unauthorized(HTTPException):
pass
43 changes: 31 additions & 12 deletions twitchio/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,42 +190,61 @@ async def _request(self, route, path, headers, utilize_bucket=True):
await self.bucket.wait_reset()
async with self.session.request(route.method, path, headers=headers, data=route.body) as resp:
try:
logger.debug(f"Received a response from a request with status {resp.status}: {await resp.json()}")
message = await resp.text(encoding="utf-8")
logger.debug(f"Received a response from a request with status {resp.status}: {message}")
except Exception:
message = None
logger.debug(f"Received a response from a request with status {resp.status} and without body")

if 500 <= resp.status <= 504:
reason = resp.reason
await asyncio.sleep(2**attempt + 1)
continue

if utilize_bucket:
reset = resp.headers.get("Ratelimit-Reset")
remaining = resp.headers.get("Ratelimit-Remaining")

self.bucket.update(reset=reset, remaining=remaining)

if 200 <= resp.status < 300:
if resp.content_type == "application/json":
return await resp.json(), False
return await resp.text(encoding="utf-8"), True
if resp.status == 401:
message_json = await resp.json()
if resp.content_type == "application/json" and message:
return json.loads(message), False

return message, True

elif resp.status == 400:
message_json = json.loads(message)
raise errors.HTTPException(
f"Failed to fulfill the request", reason=message_json.get("message", ""), status=resp.status
)

elif resp.status == 401:
message_json = json.loads(message)
if "Invalid OAuth token" in message_json.get("message", ""):
try:
await self._generate_login()
continue
except:
raise errors.Unauthorized(
"Your oauth token is invalid, and a new one could not be generated"
)
print(resp.reason, message_json, resp)
raise errors.Unauthorized("You're not authorized to use this route.")
if resp.status == 429:

raise errors.Unauthorized(
"You're not authorized to use this route.",
reason=message_json.get("message", ""),
status=resp.status,
)

elif resp.status == 429:
reason = "Ratelimit Reached"

if not utilize_bucket: # non Helix APIs don't have ratelimit headers
await asyncio.sleep(3**attempt + 1)

continue
raise errors.HTTPException(
f"Failed to fulfil request ({resp.status}).", reason=resp.reason, status=resp.status
)

raise errors.HTTPException(f"Failed to fulfill the request", reason=resp.reason, status=resp.status)
raise errors.HTTPException("Failed to reach Twitch API", reason=reason, status=resp.status)

async def _generate_login(self):
Expand Down

0 comments on commit 9937590

Please sign in to comment.