def example_1(): def key_error_handler(*args, **kwargs): print 'KeyError handler' print args, kwargs with ErrorManager.for_KeyError(handler=key_error_handler): d = {} d['fake_item']
def example_3(): def success_handler(*args, **kwargs): print 'success handler' print args, kwargs with ErrorManager.for_all(on_success=success_handler): d = {'item': 0} d['item']
def example_2(): def default_error_handler(*args, **kwargs): print 'defaul handler' print args, kwargs with ErrorManager.for_all(on_default=default_error_handler): d = {} d['fake_item']
def __init__(self, orchestrator, instance_config): # The Orchestrator object this manager belongs to self._orchestrator = orchestrator # The global config of the orchestrator self._config = orchestrator.config # ManagerConfig for this instance self._instance_config = instance_config # Named used for display/system purposes self._name = '{}{:03}'.format(self.key, instance_config.id) # Used to track errors, warnings and info messages in the client and the error status. self._error_manager = ErrorManager() # Set by children when they grab a peer_port self._peer_port = None # Registry for the periodic tasks self._periodic_tasks = [] # Current instance of SessionStats, as last obtained from the client self._session_stats = None # Has the client been fully initialized (all initial data loaded) self._initialized = False # Initialization time from launch in seconds self._initialize_time_seconds = None # When the instance was launched self._launch_datetime = None
class Manager(ABC): key = None config_model = None def __init__(self, orchestrator, instance_config): # The Orchestrator object this manager belongs to self._orchestrator = orchestrator # The global config of the orchestrator self._config = orchestrator.config # ManagerConfig for this instance self._instance_config = instance_config # Named used for display/system purposes self._name = '{}{:03}'.format(self.key, instance_config.id) # Used to track errors, warnings and info messages in the client and the error status. self._error_manager = ErrorManager() # Set by children when they grab a peer_port self._peer_port = None # Registry for the periodic tasks self._periodic_tasks = [] # Current instance of SessionStats, as last obtained from the client self._session_stats = None # Has the client been fully initialized (all initial data loaded) self._initialized = False # Initialization time from launch in seconds self._initialize_time_seconds = None # When the instance was launched self._launch_datetime = None @property def initialized(self): return self._initialized @property def name(self): return self._name @property def config(self): return self._config @property def instance_config(self): return self._instance_config @property def session_stats(self): return self._session_stats @property @abstractmethod def peer_port(self): pass @abstractmethod async def force_reannounce(self, info_hash): pass @abstractmethod async def force_recheck(self, info_hash): pass @abstractmethod async def move_data(self, info_hash, download_path): pass @abstractmethod async def pause_torrent(self, info_hash): pass @abstractmethod async def resume_torrent(self, info_hash): pass @abstractmethod async def rename_torrent(self, info_hash, name): pass @abstractmethod def launch(self): logger.info('Launching {}', self._name) self._launch_datetime = timezone_now() @abstractmethod async def shutdown(self): pass @abstractmethod def get_info_dict(self): return { 'type': self.key, 'name': self._name, 'peer_port': self.peer_port, 'config': self.instance_config.to_dict(), 'initialized': self._initialized, 'status': self._error_manager.status, 'errors': self._error_manager.to_dict(), 'session_stats': self._session_stats.to_dict() if self._session_stats else None, } @abstractmethod def get_debug_dict(self): data = self.get_info_dict() data.update({ 'initialize_time_seconds': self._initialize_time_seconds, }) return data @abstractmethod async def add_torrent(self, torrent, download_path, name): pass @abstractmethod async def remove_torrent(self, info_hash): pass async def _run_periodic_task_if_needed(self, current_time, task): start = time.time() ran = await task.run_if_needed(current_time) if ran: logger.debug('{}.{} took {:.3f}', self._name, task.fn.__name__, time.time() - start) return ran async def _run_periodic_tasks(self): current_time = time.time() for task in self._periodic_tasks: try: ran = await self._run_periodic_task_if_needed( current_time, task) if ran: self._error_manager.clear_error(task.fn.__name__) except CancelledError: raise except Exception: message = 'Periodic task {} running every {}s crashed'.format( task.fn.__name__, task.interval_seconds) self._error_manager.add_error(severity=Severity.ERROR, key=task.fn.__name__, message=message, traceback=traceback.format_exc()) logger.exception(message) def _can_clean_directory(self, directory): items = os.listdir(directory) if self._config.clean_torrent_file_on_remove: return all( f.lower().endswith('.torrent') or f == 'ReleaseInfo2.txt' for f in items) else: return len(items) == 0 def clean_torrent_directories(self, download_path, torrent_name): try: if not self._config.clean_directories_on_remove: logger.debug( 'Directory clean on remove is disabled in config.') return start_dir = os.path.join(download_path, torrent_name) if not os.path.isdir(start_dir): start_dir = download_path if not os.path.isdir(start_dir): logger.debug('Directory for {}/{} not found.'.format( download_path, torrent_name)) return while self._can_clean_directory(start_dir): logger.info( 'Removing cleanable directory {}.'.format(start_dir)) shutil.rmtree(start_dir) start_dir = os.path.dirname(start_dir) except Exception as exc: self._error_manager.add_error( Severity.ERROR, 'clean_torrent_directories', 'Unable to clean torrent directories for {}/{}.'.format( download_path, torrent_name), traceback.format_exc(), )