diff --git a/src/epplibwrapper/client.py b/src/epplibwrapper/client.py index f43ee41e4..1bbda80e7 100644 --- a/src/epplibwrapper/client.py +++ b/src/epplibwrapper/client.py @@ -15,6 +15,7 @@ from django.conf import settings from .cert import Cert, Key from .errors import LoginError, RegistryError +from .socket import Socket from .utility.pool import EppConnectionPool logger = logging.getLogger(__name__) @@ -41,7 +42,6 @@ class EPPLibWrapper: def __init__(self) -> None: """Initialize settings which will be used for all connections.""" - # prepare (but do not send) a Login command self._login = commands.Login( cl_id=settings.SECRET_REGISTRY_CL_ID, @@ -51,6 +51,7 @@ class EPPLibWrapper: "urn:ietf:params:xml:ns:contact-1.0", ], ) + # establish a client object with a TCP socket transport self._client = Client( SocketTransport( @@ -71,19 +72,23 @@ class EPPLibWrapper: # Occasionally pings the registry to keep the connection alive "keepalive": settings.POOL_KEEP_ALIVE, } - self._pool = EppConnectionPool( - client=self._client, login=self._login, options=options - ) + + self._pool = None + if not settings.DEBUG or self._test_registry_connection_success(): + self._pool = EppConnectionPool( + client=self._client, login=self._login, options=options + ) + else: + logger.warning("Cannot contact the Registry") + # TODO - signal that the app may need to restart? def _send(self, command): """Helper function used by `send`.""" cmd_type = command.__class__.__name__ try: - # We won't have an EPP connection locally, - # shortcut this and raise an err - # TODO - implement a timeout in _pool.get() - if settings.DEBUG: + if self._pool is None: raise LoginError + # TODO - add a timeout with self._pool.get() as connection: response = connection.send(command) except (ValueError, ParsingError) as err: @@ -127,6 +132,18 @@ class EPPLibWrapper: else: # don't try again raise err + def _test_registry_connection_success(self): + """Check that determines if our login + credentials are valid, and/or if the Registrar + can be contacted + """ + socket = Socket(self._login, self._client) + can_login = False + # Something went wrong if this doesn't exist + if hasattr(socket, "test_connection_success"): + can_login = socket.test_connection_success() + return can_login + try: # Initialize epplib diff --git a/src/epplibwrapper/socket.py b/src/epplibwrapper/socket.py index 33db76a73..d25d823f1 100644 --- a/src/epplibwrapper/socket.py +++ b/src/epplibwrapper/socket.py @@ -1,7 +1,9 @@ import logging +from time import sleep try: from epplib import commands + from epplib.client import Client except ImportError: pass @@ -14,7 +16,7 @@ logger = logging.getLogger(__name__) class Socket: """Context manager which establishes a TCP connection with registry.""" - def __init__(self, client, login) -> None: + def __init__(self, client: commands.Login, login: Client) -> None: """Save the epplib client and login details.""" self.client = client self.login = login @@ -27,15 +29,39 @@ class Socket: """Runs disconnect(), which closes a connection with EPPLib.""" self.disconnect() - def connect(self): + def connect(self, pass_response_only=False): """Use epplib to connect.""" self.client.connect() response = self.client.send(self.login) - if response.code >= 2000: + if self.is_login_error(response.code): self.client.close() raise LoginError(response.msg) return self.client + def is_login_error(self, code): + return code >= 2000 + + def test_connection_success(self): + """Tests if a successful connection can be made with the registry""" + # Something went wrong if this doesn't exist + if not hasattr(self.client, "connect"): + return False + + counter = 0 # we'll try 3 times + while True: + try: + self.client.connect() + response = self.client.send(self.login) + except LoginError as err: + if err.should_retry() and counter < 3: + counter += 1 + sleep((counter * 50) / 1000) # sleep 50 ms to 150 ms + else: # don't try again + return False + else: + self.disconnect() + return not self.is_login_error(response.code) + def disconnect(self): """Close the connection.""" try: