Catch errors when calling Discord API and re-try
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
import os
|
import os
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
from requests import exceptions
|
||||||
|
|
||||||
from app.twitch_client import StreamInformation
|
from app.twitch_client import StreamInformation
|
||||||
|
|
||||||
@@ -13,91 +15,116 @@ class DiscordClient:
|
|||||||
self._webhook_url = os.environ["DISCORD_WEBHOOK_URL"]
|
self._webhook_url = os.environ["DISCORD_WEBHOOK_URL"]
|
||||||
|
|
||||||
def send_information_to_discord(
|
def send_information_to_discord(
|
||||||
self, stream: StreamInformation, profile_image: str
|
self,
|
||||||
|
stream: StreamInformation,
|
||||||
|
profile_image: str,
|
||||||
|
retry_count: int = 0,
|
||||||
) -> None:
|
) -> None:
|
||||||
logger.info("Sending a message with an embed to the webhook...")
|
logger.info("Sending a message with an embed to the webhook...")
|
||||||
streamer_url = f"https://www.twitch.tv/{stream.user_login}"
|
streamer_url = f"https://www.twitch.tv/{stream.user_login}"
|
||||||
response = requests.post(
|
try:
|
||||||
url=f"{self._webhook_url}?wait=true",
|
response = requests.post(
|
||||||
json={
|
url=f"{self._webhook_url}?wait=true",
|
||||||
"username": "Oak Tree",
|
json={
|
||||||
"avatar_url": "https://i.imgur.com/DBOuwjx.png",
|
"username": "Oak Tree",
|
||||||
"content": f"@everyone {stream.user_name} went live!",
|
"avatar_url": "https://i.imgur.com/DBOuwjx.png",
|
||||||
"embeds": [
|
"content": f"@everyone {stream.user_name} went live!",
|
||||||
{
|
"embeds": [
|
||||||
"title": stream.title,
|
{
|
||||||
"color": 8388863,
|
"title": stream.title,
|
||||||
"timestamp": stream.started_at,
|
"color": 8388863,
|
||||||
"url": streamer_url,
|
"timestamp": stream.started_at,
|
||||||
"author": {
|
|
||||||
"name": stream.user_name,
|
|
||||||
"url": streamer_url,
|
"url": streamer_url,
|
||||||
"icon_url": profile_image,
|
"author": {
|
||||||
},
|
"name": stream.user_name,
|
||||||
"image": {"url": stream.thumbnail_url},
|
"url": streamer_url,
|
||||||
"fields": [
|
"icon_url": profile_image,
|
||||||
{
|
|
||||||
"name": "Game",
|
|
||||||
"value": stream.game_name,
|
|
||||||
"inline": True,
|
|
||||||
},
|
},
|
||||||
{
|
"image": {"url": stream.thumbnail_url},
|
||||||
"name": "Viewers",
|
"fields": [
|
||||||
"value": stream.viewer_count,
|
{
|
||||||
"inline": True,
|
"name": "Game",
|
||||||
},
|
"value": stream.game_name,
|
||||||
],
|
"inline": True,
|
||||||
}
|
},
|
||||||
],
|
{
|
||||||
},
|
"name": "Viewers",
|
||||||
)
|
"value": stream.viewer_count,
|
||||||
|
"inline": True,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
|
|
||||||
self._notification_msg_id = response.json()["id"]
|
self._notification_msg_id = response.json()["id"]
|
||||||
logger.info("Stream information sent with ping to Discord.")
|
logger.info("Stream information sent with ping to Discord.")
|
||||||
|
except (exceptions.ConnectionError, exceptions.HTTPError) as err:
|
||||||
|
logger.opt(exception=err).warning(
|
||||||
|
"Could not send embed to Discord."
|
||||||
|
)
|
||||||
|
if retry_count > 5:
|
||||||
|
logger.warning("Aborted sending the embed to Discord.")
|
||||||
|
return
|
||||||
|
retry_count += 1
|
||||||
|
logger.info(f"Retrying finalize in {retry_count * 5} seconds.")
|
||||||
|
sleep(retry_count * 5)
|
||||||
|
self.send_information_to_discord(
|
||||||
|
stream=stream,
|
||||||
|
profile_image=profile_image,
|
||||||
|
retry_count=retry_count,
|
||||||
|
)
|
||||||
|
|
||||||
def update_information_on_discord(
|
def update_information_on_discord(
|
||||||
self, stream: StreamInformation, profile_image: str
|
self, stream: StreamInformation, profile_image: str
|
||||||
) -> None:
|
) -> None:
|
||||||
logger.info("Updating stream information on Discord...")
|
logger.info("Updating stream information on Discord...")
|
||||||
streamer_url = f"https://www.twitch.tv/{stream.user_login}"
|
streamer_url = f"https://www.twitch.tv/{stream.user_login}"
|
||||||
response = requests.patch(
|
try:
|
||||||
url=f"{self._webhook_url}/messages/{self._notification_msg_id}",
|
response = requests.patch(
|
||||||
json={
|
url=f"{self._webhook_url}/messages/{self._notification_msg_id}",
|
||||||
"embeds": [
|
json={
|
||||||
{
|
"embeds": [
|
||||||
"title": stream.title,
|
{
|
||||||
"color": 8388863,
|
"title": stream.title,
|
||||||
"timestamp": stream.started_at,
|
"color": 8388863,
|
||||||
"url": streamer_url,
|
"timestamp": stream.started_at,
|
||||||
"author": {
|
|
||||||
"name": f"{stream.user_name}",
|
|
||||||
"url": streamer_url,
|
"url": streamer_url,
|
||||||
"icon_url": profile_image,
|
"author": {
|
||||||
},
|
"name": f"{stream.user_name}",
|
||||||
"image": {"url": stream.thumbnail_url},
|
"url": streamer_url,
|
||||||
"fields": [
|
"icon_url": profile_image,
|
||||||
{
|
|
||||||
"name": "Game",
|
|
||||||
"value": stream.game_name,
|
|
||||||
"inline": True,
|
|
||||||
},
|
},
|
||||||
{
|
"image": {"url": stream.thumbnail_url},
|
||||||
"name": "Viewers",
|
"fields": [
|
||||||
"value": stream.viewer_count,
|
{
|
||||||
"inline": True,
|
"name": "Game",
|
||||||
},
|
"value": stream.game_name,
|
||||||
],
|
"inline": True,
|
||||||
}
|
},
|
||||||
],
|
{
|
||||||
},
|
"name": "Viewers",
|
||||||
)
|
"value": stream.viewer_count,
|
||||||
response.raise_for_status()
|
"inline": True,
|
||||||
logger.info("Message embed content updated.")
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
logger.info("Message embed content updated.")
|
||||||
|
except (exceptions.ConnectionError, exceptions.HTTPError) as err:
|
||||||
|
logger.opt(exception=err).warning(
|
||||||
|
"Could not update embed content due to connection error. "
|
||||||
|
"Not retrying due to this not being important."
|
||||||
|
)
|
||||||
|
|
||||||
def finalize_information_on_discord(
|
def finalize_information_on_discord(
|
||||||
self, streamer_name, vod_url: str | None
|
self, streamer_name, vod_url: str | None, retry_count: int = 0
|
||||||
) -> None:
|
) -> None:
|
||||||
logger.info("Finalizing stream information on Discord...")
|
logger.info("Finalizing stream information on Discord...")
|
||||||
if not self._notification_msg_id:
|
if not self._notification_msg_id:
|
||||||
@@ -105,19 +132,38 @@ class DiscordClient:
|
|||||||
return
|
return
|
||||||
|
|
||||||
if not vod_url:
|
if not vod_url:
|
||||||
vod_url = "None available. Please contact the developer."
|
vod_url = "None available."
|
||||||
|
|
||||||
response = requests.patch(
|
try:
|
||||||
url=f"{self._webhook_url}/messages/{self._notification_msg_id}",
|
response = requests.patch(
|
||||||
json={
|
url=f"{self._webhook_url}/messages/{self._notification_msg_id}",
|
||||||
"username": "Oak Tree",
|
json={
|
||||||
"avatar_url": "https://i.imgur.com/DBOuwjx.png",
|
"username": "Oak Tree",
|
||||||
"content": (
|
"avatar_url": "https://i.imgur.com/DBOuwjx.png",
|
||||||
f"{streamer_name} stopped the stream. Check out the VOD!"
|
"content": (
|
||||||
f"\n{vod_url}"
|
f"{streamer_name} stopped the stream. Check out the VOD!"
|
||||||
),
|
f"\n{vod_url}"
|
||||||
"embeds": [],
|
),
|
||||||
},
|
"embeds": [],
|
||||||
)
|
},
|
||||||
response.raise_for_status()
|
)
|
||||||
logger.info("Message updated with VOD.")
|
response.raise_for_status()
|
||||||
|
logger.info("Message updated with VOD.")
|
||||||
|
except (exceptions.ConnectionError, exceptions.HTTPError) as err:
|
||||||
|
logger.opt(exception=err).warning(
|
||||||
|
"Could not finalize embed on Discord."
|
||||||
|
)
|
||||||
|
if retry_count > 5:
|
||||||
|
logger.warning(
|
||||||
|
"Aborted finalizing the embed on Discord. "
|
||||||
|
"It will be stuck on the last stream update."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
retry_count += 1
|
||||||
|
logger.info(f"Retrying finalize in {retry_count * 5} seconds.")
|
||||||
|
sleep(retry_count * 5)
|
||||||
|
self.finalize_information_on_discord(
|
||||||
|
streamer_name=streamer_name,
|
||||||
|
vod_url=vod_url,
|
||||||
|
retry_count=retry_count,
|
||||||
|
)
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ import pytest
|
|||||||
def mock_loggers():
|
def mock_loggers():
|
||||||
with (
|
with (
|
||||||
mock.patch("loguru.logger.info") as info_logger,
|
mock.patch("loguru.logger.info") as info_logger,
|
||||||
|
mock.patch("loguru.logger.warning") as warning_logger,
|
||||||
mock.patch("loguru.logger.error") as error_logger,
|
mock.patch("loguru.logger.error") as error_logger,
|
||||||
):
|
):
|
||||||
mocked_loggers = namedtuple(
|
mocked_loggers = namedtuple(
|
||||||
"mocked_loggers", ["info_logger", "error_logger"]
|
"mocked_loggers", ["info_logger", "warning_logger", "error_logger"]
|
||||||
)
|
)
|
||||||
yield mocked_loggers(info_logger, error_logger)
|
yield mocked_loggers(info_logger, warning_logger, error_logger)
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ from unittest import mock
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import requests_mock
|
import requests_mock
|
||||||
from requests import HTTPError
|
|
||||||
|
|
||||||
from app.discord_client import DiscordClient
|
from app.discord_client import DiscordClient
|
||||||
from app.twitch_client import StreamInformation
|
from app.twitch_client import StreamInformation
|
||||||
@@ -74,12 +73,15 @@ def test_send_information_to_discord_fails(mock_loggers):
|
|||||||
requests_mocker.post(url="https://test", status_code=400)
|
requests_mocker.post(url="https://test", status_code=400)
|
||||||
|
|
||||||
discord_client = DiscordClient()
|
discord_client = DiscordClient()
|
||||||
with pytest.raises(HTTPError):
|
discord_client.send_information_to_discord(
|
||||||
discord_client.send_information_to_discord(
|
stream=stream, profile_image="", retry_count=6
|
||||||
stream=stream, profile_image=""
|
)
|
||||||
)
|
|
||||||
|
|
||||||
assert len(mock_loggers.info_logger.call_args_list) == 1
|
assert len(mock_loggers.info_logger.call_args_list) == 1
|
||||||
assert mock_loggers.info_logger.call_args.args[0] == (
|
assert mock_loggers.info_logger.call_args.args[0] == (
|
||||||
"Sending a message with an embed to the webhook..."
|
"Sending a message with an embed to the webhook..."
|
||||||
)
|
)
|
||||||
|
assert len(mock_loggers.warning_logger.call_args_list) == 1
|
||||||
|
assert mock_loggers.warning_logger.call_args.args[0] == (
|
||||||
|
"Aborted sending the embed to Discord."
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user