Skip to content

Commit

Permalink
Added "back" exception handling for the download clients. (#9774)
Browse files Browse the repository at this point in the history
* Added "back" exception handling for the download clients.
* This is needed because we want to raise exceptions when a connection error occurs.
The downloadhandler will remove tracked info_hashes when it doesn't get them back from the client. We don't want to untrack info_hash because it doesn't get them back, due to a connection error.

* Log resource_name.

* Fix pylints
  • Loading branch information
p0psicles authored Aug 7, 2021
1 parent 7e0f0cf commit 64c8fc5
Show file tree
Hide file tree
Showing 13 changed files with 196 additions and 88 deletions.
17 changes: 12 additions & 5 deletions medusa/clients/nzb/nzbget.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from medusa import app
from medusa.common import Quality
from medusa.helper.common import try_int
from medusa.helper.exceptions import DownloadClientConnectionException
from medusa.logger.adapters.style import BraceAdapter

import ttl_cache
Expand Down Expand Up @@ -56,7 +57,7 @@ def nzb_connection(url):
return False


def test_authentication(host, username, password, use_https):
def test_authentication(host=None, username=None, password=None, use_https=False):
"""
Test NZBget client connection.
Expand Down Expand Up @@ -197,10 +198,13 @@ def _get_nzb_queue():
)

if not nzb_connection(url):
return False
raise DownloadClientConnectionException('Error while fetching nzbget queue')

nzb_get_rpc = ServerProxy(url)
nzb_groups = nzb_get_rpc.listgroups()
try:
nzb_groups = nzb_get_rpc.listgroups()
except ConnectionRefusedError as error:
raise DownloadClientConnectionException(f'Error while fetching nzbget history. Error: {error}')

return nzb_groups

Expand All @@ -216,10 +220,13 @@ def _get_nzb_history():
)

if not nzb_connection(url):
return False
raise DownloadClientConnectionException('Error while fetching nzbget history')

nzb_get_rpc = ServerProxy(url)
nzb_groups = nzb_get_rpc.history()
try:
nzb_groups = nzb_get_rpc.history()
except ConnectionRefusedError as error:
raise DownloadClientConnectionException(f'Error while fetching nzbget history. Error: {error}')

return nzb_groups

Expand Down
18 changes: 14 additions & 4 deletions medusa/clients/nzb/sab.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,19 @@

from medusa import app
from medusa.helper.common import sanitize_filename
from medusa.helper.exceptions import DownloadClientConnectionException
from medusa.logger.adapters.style import BraceAdapter
from medusa.session.core import ClientSession
from medusa.session.core import MedusaSession

from requests.compat import urljoin
from requests.exceptions import ConnectionError

import ttl_cache

log = BraceAdapter(logging.getLogger(__name__))
log.logger.addHandler(logging.NullHandler())

session = ClientSession()
session = MedusaSession()


def send_nzb(nzb):
Expand Down Expand Up @@ -209,7 +211,11 @@ def _get_nzb_queue(host=None):
'limit': 100
}

data = session.get_json(url, params=params, verify=False)
try:
data = session.get_json(url, params=params, verify=False)
except ConnectionError as error:
raise DownloadClientConnectionException(f'Error while fetching sabnzbd queue. Error: {error}')

if not data:
log.info('Error connecting to sab, no data returned')
else:
Expand All @@ -234,7 +240,11 @@ def _get_nzb_history(host=None):
'limit': 100
}

data = session.get_json(url, params=params, verify=False)
try:
data = session.get_json(url, params=params, verify=False)
except ConnectionError as error:
raise DownloadClientConnectionException(f'Error while fetching sabnzbd history. Error: {error}')

if not data:
log.info('Error connecting to sab, no data returned')
else:
Expand Down
12 changes: 8 additions & 4 deletions medusa/clients/torrent/deluge.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from medusa import app
from medusa.clients.torrent.generic import GenericClient
from medusa.helper.exceptions import DownloadClientConnectionException
from medusa.helpers import (
get_extension,
is_already_processed_media,
Expand Down Expand Up @@ -215,7 +216,6 @@ def _get_auth(self):
{'name': self.name})
return None

self._torrent_properties('e4d44da9e71a8f4411bc3fd82aad7689cfa0f07f')
return self.auth

def _add_torrent_uri(self, result):
Expand Down Expand Up @@ -489,9 +489,13 @@ def _torrent_properties(self, info_hash):
})

log.debug('Checking {client} torrent {hash} status.', {'client': self.name, 'hash': info_hash})
if not self._request(method='post', data=post_data) or self.response.json()['error']:
log.warning('Error while fetching torrent {hash} status.', {'hash': info_hash})
return

try:
if not self._request(method='post', data=post_data) or self.response.json()['error']:
log.warning('Error while fetching torrent {hash} status.', {'hash': info_hash})
return
except RequestException as error:
raise DownloadClientConnectionException(f'Error while fetching torrent info_hash {info_hash}. Error: {error}')

return self.response.json()['result']

Expand Down
8 changes: 5 additions & 3 deletions medusa/clients/torrent/deluged.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
from medusa import app
from medusa.clients.torrent.deluge import read_torrent_status
from medusa.clients.torrent.generic import GenericClient
from medusa.helper.exceptions import DownloadClientConnectionException
from medusa.logger.adapters.style import BraceAdapter
from medusa.schedulers.download_handler import ClientStatus

from requests.exceptions import RequestException

log = BraceAdapter(logging.getLogger(__name__))
log.logger.addHandler(logging.NullHandler())
Expand Down Expand Up @@ -231,8 +233,7 @@ def get_status(self, info_hash):
```
"""
if not self.connect():
log.warning('Error while fetching torrents status')
return
raise DownloadClientConnectionException(f'Error while fetching torrent info_hash {info_hash}')

torrent = self.drpc._torrent_properties(info_hash)
if not torrent:
Expand Down Expand Up @@ -312,7 +313,6 @@ def test(self):
"""
try:
self.connect()
# self._torrent_properties('e4d44da9e71a8f4411bc3fd82aad7689cfa0f07f')
except Exception:
return False
else:
Expand Down Expand Up @@ -539,6 +539,8 @@ def _torrent_properties(self, info_hash):
torrent_data = self.client.core.get_torrent_status(
info_hash, ('name', 'hash', 'progress', 'state', 'ratio', 'stop_ratio',
'is_seed', 'is_finished', 'paused', 'files', 'download_location'))
except RequestException as error:
raise DownloadClientConnectionException(f'Error while fetching torrent info_hash {info_hash}. Error: {error}')
except Exception:
log.warning('Error while fetching torrent {hash} status.', {'hash': info_hash})
return
Expand Down
47 changes: 33 additions & 14 deletions medusa/clients/torrent/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@
import certifi

from medusa import app, db
from medusa.helper.common import http_code_description
from medusa.logger.adapters.style import BraceAdapter
from medusa.session.core import ClientSession

import requests


log = BraceAdapter(logging.getLogger(__name__))
log.logger.addHandler(logging.NullHandler())
Expand Down Expand Up @@ -54,27 +57,43 @@ def __init__(self, name, host=None, username=None, password=None, torrent_path=N

def _request(self, method='get', params=None, data=None, files=None, cookies=None):

self.response = self.session.request(
method, self.url, params=params, data=data, files=files, timeout=60, cookies=cookies,
verify=self.verify if app.TORRENT_VERIFY_CERT else False
)
if not self.response:
log.warning('{name} {method} call to {url} failed!', {
'name': self.name, 'method': method.upper(), 'url': self.url
})
self.message = f'Connect to {self.name} on "{self.host}" failed!'
try:
self.response = self.session.request(
method, self.url, params=params, data=data, files=files, timeout=60, cookies=cookies,
verify=self.verify if app.TORRENT_VERIFY_CERT else False
)
except (requests.exceptions.MissingSchema, requests.exceptions.InvalidURL) as error:
log.warning('{name}: Invalid Host: {error}', {'name': self.name, 'error': error})
return False
if self.response.status_code >= 400:
log.warning('{name}: Unable to reach torrent client. Reason: {reason}', {
'name': self.name, 'reason': self.response.reason
})
self.message = f'Failed to connect to {self.name} reason: {self.response.reason}'
except requests.exceptions.RequestException as error:
log.warning('{name}: Error occurred during request: {error}',
{'name': self.name, 'error': error})
# We want to raise connection errors for the download_handler. As we need to know
# explicitely if there was a connection error when untracking tracked torrents/nzb.
raise
except Exception as error:
log.error('{name}: Unknown exception raised when sending torrent to'
' {name}: {error}', {'name': self.name, 'error': error})
return False

if self.response.status_code == 401:
log.error('{name}: Invalid Username or Password,'
' check your config', {'name': self.name})
return False

code_description = http_code_description(self.response.status_code)

if code_description is not None:
log.info('{name}: {code}',
{'name': self.name, 'code': code_description})
return False

log.debug('{name}: Response to {method} request is {response}', {
'name': self.name,
'method': method.upper(),
'response': self.response.text[0:1024] + '...' if len(self.response.text) > 1027 else self.response.text
})

return True

def _get_auth(self):
Expand Down
14 changes: 11 additions & 3 deletions medusa/clients/torrent/qbittorrent.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@

from medusa import app
from medusa.clients.torrent.generic import GenericClient
from medusa.helper.exceptions import DownloadClientConnectionException
from medusa.logger.adapters.style import BraceAdapter
from medusa.schedulers.download_handler import ClientStatus

from requests.auth import HTTPDigestAuth
from requests.compat import urljoin
from requests.exceptions import RequestException

import ttl_cache

Expand Down Expand Up @@ -293,6 +295,9 @@ def remove_torrent_data(self, info_hash):
def _get_torrents(self, filter=None, category=None, sort=None):
"""Get all torrents from qbittorrent api."""
params = {}
if not self.api:
raise DownloadClientConnectionException('Error while fetching torrent. Not authenticated.')

if self.api >= (2, 0, 0):
self.url = urljoin(self.host, 'api/v2/torrents/info')
if filter:
Expand All @@ -304,9 +309,12 @@ def _get_torrents(self, filter=None, category=None, sort=None):
else:
self.url = urljoin(self.host, 'json/torrents')

if not self._request(method='get', params=params, cookies=self.session.cookies):
log.warning('Error while fetching torrents.')
return []
try:
if not self._request(method='get', params=params, cookies=self.session.cookies):
log.warning('Error while fetching torrents.')
return []
except RequestException as error:
raise DownloadClientConnectionException(f'Error while fetching torrent. Error: {error}')

return self.response.json()

Expand Down
34 changes: 26 additions & 8 deletions medusa/clients/torrent/rtorrent.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from medusa import app
from medusa.clients.torrent.generic import GenericClient
from medusa.helper.exceptions import DownloadClientConnectionException
from medusa.logger.adapters.style import BraceAdapter
from medusa.schedulers.download_handler import ClientStatus

Expand Down Expand Up @@ -51,10 +52,13 @@ def _get_auth(self):
if app.SSL_CA_BUNDLE:
tp_kwargs['check_ssl_cert'] = app.SSL_CA_BUNDLE

if self.username and self.password:
self.auth = RTorrent(self.host, self.username, self.password, True, tp_kwargs=tp_kwargs)
else:
self.auth = RTorrent(self.host, None, None, True)
try:
if self.username and self.password:
self.auth = RTorrent(self.host, self.username, self.password, True, tp_kwargs=tp_kwargs)
else:
self.auth = RTorrent(self.host, None, None, True)
except Exception as error: # No request/connection specific exception thrown.
raise DownloadClientConnectionException(f'Unable to authenticate with rtorrent client: {error}')

return self.auth

Expand Down Expand Up @@ -82,7 +86,11 @@ def _add_torrent_uri(self, result):
try:
params = self._get_params(result)
# Send magnet to rTorrent and start it
torrent = self.auth.load_magnet(result.url, result.hash, start=True, params=params)
try:
torrent = self.auth.load_magnet(result.url, result.hash, start=True, params=params)
except DownloadClientConnectionException:
return False

if not torrent:
return False

Expand All @@ -101,7 +109,11 @@ def _add_torrent_file(self, result):
try:
params = self._get_params(result)
# Send torrent to rTorrent and start it
torrent = self.auth.load_torrent(result.content, start=True, params=params)
try:
torrent = self.auth.load_torrent(result.content, start=True, params=params)
except DownloadClientConnectionException:
return False

if not torrent:
return False

Expand Down Expand Up @@ -132,7 +144,10 @@ def test_authentication(self):
def pause_torrent(self, info_hash):
"""Get torrent and pause."""
log.info('Pausing {client} torrent {hash} status.', {'client': self.name, 'hash': info_hash})
torrent = self.auth.find_torrent(info_hash.upper())
try:
torrent = self.auth.find_torrent(info_hash.upper())
except DownloadClientConnectionException:
return False

if not torrent:
log.debug('Could not locate torrent with {hash} status.', {'hash': info_hash})
Expand All @@ -143,7 +158,10 @@ def pause_torrent(self, info_hash):
def remove_torrent(self, info_hash):
"""Get torrent and remove."""
log.info('Removing {client} torrent {hash} status.', {'client': self.name, 'hash': info_hash})
torrent = self.auth.find_torrent(info_hash.upper())
try:
torrent = self.auth.find_torrent(info_hash.upper())
except DownloadClientConnectionException:
return False

if not torrent:
log.debug('Could not locate torrent with {hash} status.', {'hash': info_hash})
Expand Down
4 changes: 2 additions & 2 deletions medusa/clients/torrent/transmission.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from medusa import app
from medusa.clients.torrent.generic import GenericClient
from medusa.helper.exceptions import DownloadClientConnectionException
from medusa.logger.adapters.style import BraceAdapter
from medusa.schedulers.download_handler import ClientStatus

Expand Down Expand Up @@ -308,8 +309,7 @@ def _torrent_properties(self, info_hash):
post_data = json.dumps({'arguments': return_params, 'method': 'torrent-get'})

if not self._request(method='post', data=post_data) or not self.check_response():
log.warning('Error while fetching torrent {hash} status.', {'hash': info_hash})
return
raise DownloadClientConnectionException(f'Error while fetching torrent {info_hash} status.')

torrent = self.response.json()['arguments']['torrents']
if not torrent:
Expand Down
11 changes: 7 additions & 4 deletions medusa/clients/torrent/utorrent.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

from medusa import app
from medusa.clients.torrent.generic import GenericClient
from medusa.helper.exceptions import DownloadClientConnectionException
from medusa.logger.adapters.style import BraceAdapter
from medusa.schedulers.download_handler import ClientStatus

Expand Down Expand Up @@ -251,11 +252,13 @@ def _get_torrents(self):
info_hash, it will get all torrents for each info_hash. We might want to cache this one.
"""
params = {'list': 1}
if not self._request(params=params):
log.warning('Error while fetching torrents.')
return []

json_response = self.response.json()
try:
self._request(params=params)
json_response = self.response.json()
except RequestException as error:
raise DownloadClientConnectionException(f'Error while fetching torrent. Error: {error}')

if json_response.get('torrents'):
return json_response['torrents']
return []
Expand Down
Loading

0 comments on commit 64c8fc5

Please sign in to comment.