Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use unique amcrest exceptions #108

Merged
merged 2 commits into from
Mar 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/amcrest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
# GNU General Public License for more details.
#
# vim:sw=4:ts=4:et

from amcrest.http import Http
from .exceptions import AmcrestError, CommError, LoginError

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'.exceptions.AmcrestError' imported but unused
'.exceptions.CommError' imported but unused
'.exceptions.LoginError' imported but unused

from .http import Http


class AmcrestCamera(object):
Expand Down
15 changes: 15 additions & 0 deletions src/amcrest/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""
amcrest.exceptions

This module contains the set of amcrest's exceptions.
"""
class AmcrestError(Exception):
pnbruckner marked this conversation as resolved.
Show resolved Hide resolved
"""General Amcrest error occurred."""


class CommError(AmcrestError):
pnbruckner marked this conversation as resolved.
Show resolved Hide resolved
"""A communication error occurred."""


class LoginError(AmcrestError):
pnbruckner marked this conversation as resolved.
Show resolved Hide resolved
"""A login error occurred."""
95 changes: 49 additions & 46 deletions src/amcrest/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,29 @@
#
# vim:sw=4:ts=4:et
import logging

import requests
from requests.adapters import HTTPAdapter

from amcrest.utils import clean_url, pretty

from amcrest.audio import Audio
from amcrest.event import Event
from amcrest.log import Log
from amcrest.motion_detection import MotionDetection
from amcrest.nas import Nas
from amcrest.network import Network
from amcrest.ptz import Ptz
from amcrest.record import Record
from amcrest.snapshot import Snapshot
from amcrest.special import Special
from amcrest.storage import Storage
from amcrest.system import System
from amcrest.user_management import UserManagement
from amcrest.video import Video

from amcrest.config import TIMEOUT_HTTP_PROTOCOL, MAX_RETRY_HTTP_CONNECTION
from .exceptions import CommError, LoginError
from .utils import clean_url, pretty

from .audio import Audio
from .event import Event
from .log import Log
from .motion_detection import MotionDetection
from .nas import Nas
from .network import Network
from .ptz import Ptz
from .record import Record
from .snapshot import Snapshot
from .special import Special
from .storage import Storage
from .system import System
from .user_management import UserManagement
from .video import Video

from .config import TIMEOUT_HTTP_PROTOCOL, MAX_RETRY_HTTP_CONNECTION

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -60,32 +62,40 @@ def __init__(self, host, port, user,
self._token = self._generate_token()
self._set_name()

def _generate_token(self):
"""Discover which authentication method to use.
def get_session(self, max_retries=None):
session = requests.Session()
max_retries = max_retries or self._retries_default
adapter = HTTPAdapter(max_retries=max_retries)
session.mount('http://', adapter)
session.mount('https://', adapter)
return session

Latest firmwares requires HttpDigestAuth
Older firmwares requires HttpBasicAuth
"""
def _generate_token(self):
"""Create authentation to use with requests."""
session = self.get_session()
url = self.__base_url('magicBox.cgi?action=getMachineName')
try:
# try old firmware first to force 401 if fails
self._authentication = 'basic'
# try old basic method
auth = requests.auth.HTTPBasicAuth(self._user, self._password)
req = requests.get(url, auth=auth)
req = session.get(url, auth=auth, timeout=self._timeout_default)
if not req.ok:
# try new digest method
auth = requests.auth.HTTPDigestAuth(
self._user, self._password)
req = session.get(
url, auth=auth, timeout=self._timeout_default)
req.raise_for_status()
except requests.RequestException as error:
_LOGGER.error(error)
raise CommError('Could not communicate with camera')
pnbruckner marked this conversation as resolved.
Show resolved Hide resolved

except requests.HTTPError:
# if 401, then try new digest method
self._authentication = 'digest'
auth = requests.auth.HTTPDigestAuth(self._user, self._password)
req = requests.get(url, auth=auth)
req.raise_for_status()
# check if user passed
result = req.text.lower()
if 'invalid' in result or 'error' in result:
_LOGGER.error('Result from camera: %s',
req.text.strip().replace('\r\n', ': '))
raise LoginError('Invalid credentials')
pnbruckner marked this conversation as resolved.
Show resolved Hide resolved

# check if user passed
if 'invalid' in req.text.lower() or \
'error' in req.text.lower():
_LOGGER.info("%s Invalid credentials", req.text)
raise
return auth

def _set_name(self):
Expand Down Expand Up @@ -117,13 +127,6 @@ def __base_url(self, param=""):
def get_base_url(self):
return self._base_url

def get_session(self, max_retries):
session = requests.Session()
adapter = HTTPAdapter(max_retries=max_retries)
session.mount('http://', adapter)
session.mount('https://', adapter)
return session

def command(self, cmd, retries=None, timeout_cmd=None):
"""
Args:
Expand All @@ -147,13 +150,13 @@ def command(self, cmd, retries=None, timeout_cmd=None):
)
resp.raise_for_status()
break
except requests.HTTPError as error:
except requests.RequestException as error:
if loop <= retries:
_LOGGER.warning("Trying again due to error %s", error)
continue
else:
_LOGGER.error("Query failed due to error %s", error)
raise
raise CommError('Could not communicate with camera')
pnbruckner marked this conversation as resolved.
Show resolved Hide resolved

_LOGGER.debug("Query worked. Exit code: <%s>", resp.status_code)
return resp
Expand Down