def scan(self) -> List[SystemFile]: if self.__first_run: self._install_scanfs() self.__first_run = False retries = 0 out = None while out is None: try: out = self.__ssh.shell("'{}' '{}'".format( self.__remote_path_to_scan_script, self.__remote_path_to_scan)) except SshcpError as e: # Suppress specific errors and retry a fixed number of times # Otherwise raise a fatal AppError if RemoteScanner.__suppress_error( e) and retries < RemoteScanner.RETRY_COUNT: self.logger.warning( "Retrying remote scan after error: {}".format(str(e))) out = None retries += 1 else: self.logger.exception("Caught an SshError") raise AppError(Localization.Error.REMOTE_SERVER_SCAN) try: remote_files = pickle.loads(out) except pickle.UnpicklingError as err: self.logger.error("Unpickling error: {}\n{}".format(str(err), out)) raise AppError(Localization.Error.REMOTE_SERVER_SCAN) return remote_files
def scan(self) -> List[SystemFile]: try: result = self.__scanner.scan() except SystemScannerError: self.logger.exception("Caught SystemScannerError") raise AppError(Localization.Error.LOCAL_SERVER_SCAN) return result
def _install_scanfs(self): self.logger.info("Installing local:{} to remote:{}".format( self.__local_path_to_scan_script, self.__remote_path_to_scan_script)) if not os.path.isfile(self.__local_path_to_scan_script): raise RemoteScannerError( "Failed to find scanfs executable at {}".format( self.__local_path_to_scan_script)) try: self.__scp.copy(local_path=self.__local_path_to_scan_script, remote_path=self.__remote_path_to_scan_script) except ScpError: self.logger.exception("Caught scp exception") raise AppError(Localization.Error.REMOTE_SERVER_INSTALL)
def run(self): self.context.logger.info("Starting SeedSync") self.context.logger.info("Platform: {}".format(platform.machine())) # Create controller controller = Controller(self.context, self.controller_persist) # Create auto queue auto_queue = AutoQueue(self.context, self.auto_queue_persist, controller) # Create web app web_app_builder = WebAppBuilder(self.context, controller, self.auto_queue_persist) web_app = web_app_builder.build() # Define child threads controller_job = ControllerJob( context=self.context.create_child_context(ControllerJob.__name__), controller=controller, auto_queue=auto_queue) webapp_job = WebAppJob(context=self.context.create_child_context( WebAppJob.__name__), web_app=web_app) do_start_controller = True # Initial checks to see if we should bother starting the controller if Seedsync._detect_incomplete_config(self.context.config): if not self.context.args.exit: do_start_controller = False self.context.logger.error("Config is incomplete") self.context.status.server.up = False self.context.status.server.error_msg = Localization.Error.SETTINGS_INCOMPLETE else: raise AppError("Config is incomplete") # Start child threads here if do_start_controller: controller_job.start() webapp_job.start() try: prev_persist_timestamp = datetime.now() # Thread loop while True: # Persist to file occasionally now = datetime.now() if (now - prev_persist_timestamp).total_seconds( ) > Constants.MIN_PERSIST_TO_FILE_INTERVAL_IN_SECS: prev_persist_timestamp = now self.persist() # Propagate exceptions webapp_job.propagate_exception() # Catch controller exceptions and keep running, but notify the web server of the error try: controller_job.propagate_exception() except AppError as exc: if not self.context.args.exit: self.context.status.server.up = False self.context.status.server.error_msg = str(exc) Seedsync.logger.exception("Caught exception") else: raise # Check if a restart is requested if web_app_builder.server_handler.is_restart_requested(): raise ServiceRestart() # Nothing else to do time.sleep(Constants.MAIN_THREAD_SLEEP_INTERVAL_IN_SECS) except Exception: self.context.logger.info("Exiting Seedsync") # This sleep is important to allow the jobs to finish setup before we terminate them # If we kill too early, the jobs may leave lingering threads around # Note: There might be a better way to ensure that job setup has completed, but this # will do for now time.sleep(Constants.MAIN_THREAD_SLEEP_INTERVAL_IN_SECS) # Join all the threads here if do_start_controller: controller_job.terminate() webapp_job.terminate() # Wait for the threads to close if do_start_controller: controller_job.join() webapp_job.join() # Last persist self.persist() # Raise any exceptions so they can be logged properly # Note: ServiceRestart and ServiceExit will be caught and handled # by outer code raise