# Path: dftimewolf/lib/errors.py
# class DFTimewolfError(Exception):
#   """Class to represent a DFTimewolfError.
# 
#   Attributes:
#     message (str): The error message.
#     name (str): Name of the module that generated the error.
#     stacktrace (Optional[str]): Stacktrace leading to the error.
#     critical (Optional[bool]): Whether the error is critical or not. Critical
#         errors interrupt the recipe execution flow.
#     unexpected (Optional[bool]): Whether the error is unexpected.
#   """
# 
#   def __init__(self,
#                message: Optional[str]=None,
#                name: Optional[str]=None,
#                stacktrace: Optional[str]=None,
#                critical: bool=False,
#                unexpected: bool=False) -> None:
#     """Initializes the DFTimewolfError with provided or default message."""
#     super(DFTimewolfError, self).__init__(message)
#     self.message = message or 'An error occurred.'
#     self.name = name
#     self.stacktrace = stacktrace
#     self.critical = critical
#     self.unexpected = unexpected
# 
# Path: dftimewolf/lib/logging_utils.py
# class WolfLogger(logging.getLoggerClass()):  # type: ignore
#   """Custom logging Class with a `success` logging function."""
# 
#   def success(self, *args: Any, **kwargs: Any) -> None:  # pylint: disable=invalid-name
#     """Logs a success message."""
#     super(WolfLogger, self).log(SUCCESS, *args, **kwargs)


import tempfile
import time
from typing import Optional, Union, Callable, List, Any
from grr_api_client import api as grr_api
from grr_api_client import errors as grr_errors
from grr_api_client.client import Client
from grr_api_client.flow import Flow
from grr_api_client.hunt import Hunt
from dftimewolf.lib.errors import DFTimewolfError
from dftimewolf.lib.logging_utils import WolfLogger
          to `grr_function`.
      kwargs (dict[str, object]): keyword arguments that are to be passed
          to `grr_function`.

    Returns:
      object: return value of the execution of grr_function(*args, **kwargs).
    Raises:
      DFTimewolfError: If approvers are required but none were specified.
    """
    approval_sent = False
    approval_url = None

    while True:
      try:
        return grr_function(*args, **kwargs)

      except grr_errors.AccessForbiddenError as exception:
        logger.info('No valid approval found: {0!s}'.format(exception))
        # If approval was already sent, just wait a bit more.
        if approval_sent:
          logger.info('Approval not yet granted, waiting {0:d}s'.format(
              self._CHECK_APPROVAL_INTERVAL_SEC))
          logger.success(approval_url)
          time.sleep(self._CHECK_APPROVAL_INTERVAL_SEC)
          continue

        # If no approvers were specified, abort.
        if not self.approvers:
          message = ('GRR needs approval but no approvers specified '
                     '(hint: use --approvers)')

# Path: dftimewolf/lib/errors.py
# class DFTimewolfError(Exception):
#   """Class to represent a DFTimewolfError.
# 
#   Attributes:
#     message (str): The error message.
#     name (str): Name of the module that generated the error.
#     stacktrace (Optional[str]): Stacktrace leading to the error.
#     critical (Optional[bool]): Whether the error is critical or not. Critical
#         errors interrupt the recipe execution flow.
#     unexpected (Optional[bool]): Whether the error is unexpected.
#   """
# 
#   def __init__(self,
#                message: Optional[str]=None,
#                name: Optional[str]=None,
#                stacktrace: Optional[str]=None,
#                critical: bool=False,
#                unexpected: bool=False) -> None:
#     """Initializes the DFTimewolfError with provided or default message."""
#     super(DFTimewolfError, self).__init__(message)
#     self.message = message or 'An error occurred.'
#     self.name = name
#     self.stacktrace = stacktrace
#     self.critical = critical
#     self.unexpected = unexpected
# 
# Path: dftimewolf/lib/logging_utils.py
# class WolfLogger(logging.getLoggerClass()):  # type: ignore
#   """Custom logging Class with a `success` logging function."""
# 
#   def success(self, *args: Any, **kwargs: Any) -> None:  # pylint: disable=invalid-name
#     """Logs a success message."""
#     super(WolfLogger, self).log(SUCCESS, *args, **kwargs)


# Path: dftimewolf/lib/collectors/grr_base.py
import tempfile
import time
from typing import Optional, Union, Callable, List, Any
from grr_api_client import api as grr_api
from grr_api_client import errors as grr_errors
from grr_api_client.client import Client
from grr_api_client.flow import Flow
from grr_api_client.hunt import Hunt
from dftimewolf.lib.errors import DFTimewolfError
from dftimewolf.lib.logging_utils import WolfLogger

          to `grr_function`.
      kwargs (dict[str, object]): keyword arguments that are to be passed
          to `grr_function`.

    Returns:
      object: return value of the execution of grr_function(*args, **kwargs).
    Raises:
      DFTimewolfError: If approvers are required but none were specified.
    """
    approval_sent = False
    approval_url = None

    while True:
      try:
        return grr_function(*args, **kwargs)

      except grr_errors.AccessForbiddenError as exception:
        logger.info('No valid approval found: {0!s}'.format(exception))
        # If approval was already sent, just wait a bit more.
        if approval_sent:
          logger.info('Approval not yet granted, waiting {0:d}s'.format(
              self._CHECK_APPROVAL_INTERVAL_SEC))
          logger.success(approval_url)
          time.sleep(self._CHECK_APPROVAL_INTERVAL_SEC)
          continue

        # If no approvers were specified, abort.
        if not self.approvers:
          message = ('GRR needs approval but no approvers specified '
                     '(hint: use --approvers)')

          raise DFTimewolfError(message, critical=True) from exception