def ReportShutdownException(): text = 'A serious error occured while trying to exit the program. Its traceback may be shown next. It should have also been written to client.log. You may need to quit the program from task manager.' HydrusData.DebugPrint(text) HydrusData.DebugPrint(traceback.format_exc()) wx.CallAfter(wx.MessageBox, traceback.format_exc()) wx.CallAfter(wx.MessageBox, text)
def _DisplayCatastrophicError(self, text): message = 'The db encountered a serious error! This is going to be written to the log as well, but here it is for a screenshot:' message += os.linesep * 2 message += text HydrusData.DebugPrint(message)
def _TryEndModal(self, value): try: self.EndModal(value) except Exception as e: HydrusData.ShowText( 'This dialog seems to have been unable to close for some reason. I am printing the stack to the log. The dialog may have already closed, or may attempt to close now. Please inform hydrus dev of this situation. I recommend you restart the client if you can. If the UI is locked, you will have to kill it via task manager.' ) HydrusData.PrintException(e) import traceback HydrusData.DebugPrint(''.join(traceback.format_stack())) try: self.Close() except: HydrusData.ShowText('The dialog would not close on command.') try: self.Destroy() except: HydrusData.ShowText('The dialog would not destroy on command.')
def THREADExitEverything(self): try: self.pub('splash_set_title_text', 'shutting down gui...') self.ShutdownView() self.pub('splash_set_title_text', 'shutting down db...') self.ShutdownModel() HydrusData.CleanRunningFile(HC.DB_DIR, 'client') except HydrusExceptions.PermissionException: pass except HydrusExceptions.ShutdownException: pass except: text = 'A serious error occured while trying to exit the program. Its traceback may be shown next. It should have also been written to client.log. You may need to quit the program from task manager.' HydrusData.DebugPrint(text) traceback.print_exc() wx.CallAfter(wx.MessageBox, traceback.format_exc()) wx.CallAfter(wx.MessageBox, text) finally: self.pub('splash_destroy')
def ShowExceptionClient(e, do_wait=True): (etype, value, tb) = sys.exc_info() if etype is None: etype = type(e) value = HydrusData.ToUnicode(e) trace = 'No error trace--here is the stack:' + os.linesep + ''.join( traceback.format_stack()) else: trace = ''.join(traceback.format_exception(etype, value, tb)) trace = HydrusData.ToUnicode(trace) pretty_value = HydrusData.ToUnicode(value) if os.linesep in pretty_value: (first_line, anything_else) = HydrusData.ToUnicode(value).split(os.linesep, 1) trace = trace + os.linesep + anything_else else: first_line = pretty_value job_key = ClientThreading.JobKey() if isinstance(e, HydrusExceptions.ShutdownException): return else: if hasattr(etype, '__name__'): title = HydrusData.ToUnicode(etype.__name__) else: title = HydrusData.ToUnicode(etype) job_key.SetVariable('popup_title', title) job_key.SetVariable('popup_text_1', first_line) job_key.SetVariable('popup_traceback', trace) text = job_key.ToString() HydrusData.Print('Exception:') HydrusData.DebugPrint(text) HG.client_controller.pub('message', job_key) if do_wait: time.sleep(1)
def DeletePath( path ): if os.path.exists( path ): MakeFileWritable( path ) try: if os.path.isdir( path ): shutil.rmtree( path ) else: os.remove( path ) except Exception as e: if 'Error 32' in HydrusData.ToUnicode( e ): # file in use by another process HydrusData.DebugPrint( 'Trying to delete ' + path + ' failed because it was in use by another process.' ) else: HydrusData.ShowText( 'Trying to delete ' + path + ' caused the following error:' ) HydrusData.ShowException( e )
def Exit(self): if HydrusGlobals.emergency_exit: self.ShutdownView() self.ShutdownModel() else: try: self.CreateSplash() idle_shutdown_action = self._options['idle_shutdown'] if idle_shutdown_action in (CC.IDLE_ON_SHUTDOWN, CC.IDLE_ON_SHUTDOWN_ASK_FIRST): idle_shutdown_max_minutes = self._options[ 'idle_shutdown_max_minutes'] time_to_stop = HydrusData.GetNow() + ( idle_shutdown_max_minutes * 60) if self.ThereIsIdleShutdownWorkDue(time_to_stop): if idle_shutdown_action == CC.IDLE_ON_SHUTDOWN_ASK_FIRST: text = 'Is now a good time for the client to do up to ' + HydrusData.ConvertIntToPrettyString( idle_shutdown_max_minutes ) + ' minutes\' maintenance work?' with ClientGUIDialogs.DialogYesNo( self._splash, text, title='Maintenance is due') as dlg_yn: if dlg_yn.ShowModal() == wx.ID_YES: HydrusGlobals.do_idle_shutdown_work = True else: HydrusGlobals.do_idle_shutdown_work = True exit_thread = threading.Thread( target=self.THREADExitEverything, name='Application Exit Thread') exit_thread.start() except: self.pub('splash_destroy') HydrusData.DebugPrint(traceback.format_exc()) HydrusGlobals.emergency_exit = True self.Exit()
def THREADBootEverything(self): try: self.CheckAlreadyRunning() self._last_shutdown_was_bad = HydrusData.LastShutdownWasBad( self.db_dir, 'client') HydrusData.RecordRunningStart(self.db_dir, 'client') self.InitModel() self.InitView() self._is_booted = True except HydrusExceptions.PermissionException as e: HydrusData.Print(e) HG.emergency_exit = True self.Exit() except Exception as e: text = 'A serious error occurred while trying to start the program. The error will be shown next in a window. More information may have been written to client.log.' HydrusData.DebugPrint( 'If the db crashed, another error may be written just above ^.' ) HydrusData.DebugPrint(text) HydrusData.DebugPrint(traceback.format_exc()) wx.CallAfter(wx.MessageBox, traceback.format_exc()) wx.CallAfter(wx.MessageBox, text) HG.emergency_exit = True self.Exit() finally: self._DestroySplash()
def Exit( self ): if HG.emergency_exit: self.ShutdownView() self.ShutdownModel() else: try: self._CreateSplash() idle_shutdown_action = self.options[ 'idle_shutdown' ] if idle_shutdown_action in ( CC.IDLE_ON_SHUTDOWN, CC.IDLE_ON_SHUTDOWN_ASK_FIRST ): idle_shutdown_max_minutes = self.options[ 'idle_shutdown_max_minutes' ] time_to_stop = HydrusData.GetNow() + ( idle_shutdown_max_minutes * 60 ) if self.ThereIsIdleShutdownWorkDue( time_to_stop ): if idle_shutdown_action == CC.IDLE_ON_SHUTDOWN_ASK_FIRST: text = 'Is now a good time for the client to do up to ' + HydrusData.ConvertIntToPrettyString( idle_shutdown_max_minutes ) + ' minutes\' maintenance work? (Will auto-no in 15 seconds)' with ClientGUIDialogs.DialogYesNo( self._splash, text, title = 'Maintenance is due' ) as dlg_yn: call_later = wx.CallLater( 15000, dlg_yn.EndModal, wx.ID_NO ) if dlg_yn.ShowModal() == wx.ID_YES: HG.do_idle_shutdown_work = True call_later.Stop() else: HG.do_idle_shutdown_work = True self.CallToThreadLongRunning( self.THREADExitEverything ) except: self._DestroySplash() HydrusData.DebugPrint( traceback.format_exc() ) HG.emergency_exit = True self.Exit()
def RecyclePath( path ): original_path = path if HC.PLATFORM_LINUX: # send2trash for Linux tries to do some Python3 str() stuff in prepping non-str paths for recycling if not isinstance( path, str ): try: path = path.encode( sys.getfilesystemencoding() ) except: HydrusData.Print( 'Trying to prepare ' + path + ' for recycling created this error:' ) HydrusData.DebugPrint( traceback.format_exc() ) return if os.path.exists( path ): MakeFileWritable( path ) try: send2trash.send2trash( path ) except: HydrusData.Print( 'Trying to recycle ' + path + ' created this error:' ) HydrusData.DebugPrint( traceback.format_exc() ) HydrusData.Print( 'It has been fully deleted instead.' ) DeletePath( original_path )
def THREADBootEverything(self): try: self.CheckAlreadyRunning() self._last_shutdown_was_bad = HydrusData.LastShutdownWasBad( self._db_dir, 'client') HydrusData.RecordRunningStart(self._db_dir, 'client') self.InitModel() self.InitView() except HydrusExceptions.PermissionException as e: HydrusData.Print(e) HydrusGlobals.emergency_exit = True self.Exit() except Exception as e: text = 'A serious error occured while trying to start the program. Its traceback will be shown next. It should have also been written to client.log.' HydrusData.DebugPrint(text) HydrusData.DebugPrint(traceback.format_exc()) wx.CallAfter(wx.MessageBox, traceback.format_exc()) wx.CallAfter(wx.MessageBox, text) HydrusGlobals.emergency_exit = True self.Exit() finally: self.pub('splash_destroy')
def _errbackHandleEmergencyError( self, failure, request ): try: self._CleanUpTempFile( request ) except: pass try: HydrusData.DebugPrint( failure.getTraceback() ) except: pass try: request.write( failure.getTraceback() ) except: pass try: request.finish() except: pass
def _errbackHandleProcessingError( self, failure, request ): self._CleanUpTempFile( request ) default_mime = HC.TEXT_HTML default_encoding = HydrusData.ToByteString if failure.type == KeyError: response_context = ResponseContext( 400, mime = default_mime, body = default_encoding( 'It appears one or more parameters required for that request were missing:' + os.linesep + failure.getTraceback() ) ) elif failure.type == HydrusExceptions.BandwidthException: response_context = ResponseContext( 509, mime = default_mime, body = default_encoding( failure.value ) ) elif failure.type == HydrusExceptions.PermissionException: response_context = ResponseContext( 401, mime = default_mime, body = default_encoding( failure.value ) ) elif failure.type == HydrusExceptions.ForbiddenException: response_context = ResponseContext( 403, mime = default_mime, body = default_encoding( failure.value ) ) elif failure.type in ( HydrusExceptions.NotFoundException, HydrusExceptions.DataMissing, HydrusExceptions.FileMissingException ): response_context = ResponseContext( 404, mime = default_mime, body = default_encoding( failure.value ) ) elif failure.type == HydrusExceptions.NetworkVersionException: response_context = ResponseContext( 426, mime = default_mime, body = default_encoding( failure.value ) ) elif failure.type == HydrusExceptions.ServerBusyException: response_context = ResponseContext( 503, mime = default_mime, body = default_encoding( failure.value ) ) elif failure.type == HydrusExceptions.SessionException: response_context = ResponseContext( 419, mime = default_mime, body = default_encoding( failure.value ) ) else: HydrusData.DebugPrint( failure.getTraceback() ) response_context = ResponseContext( 500, mime = default_mime, body = default_encoding( 'The repository encountered an error it could not handle! Here is a dump of what happened, which will also be written to your client.log file. If it persists, please forward it to [email protected]:' + os.linesep * 2 + failure.getTraceback() ) ) request.hydrus_response_context = response_context return request
def RequestsCheckResponse( response ): if not response.ok: error_text = response.content if len( error_text ) > 1024: large_chunk = error_text[:4096] smaller_chunk = large_chunk[:256] HydrusData.DebugPrint( large_chunk ) error_text = 'The server\'s error text was too long to display. The first part follows, while a larger chunk has been written to the log.' error_text += os.linesep error_text += smaller_chunk if response.status_code == 304: eclass = HydrusExceptions.NotModifiedException elif response.status_code == 401: eclass = HydrusExceptions.PermissionException elif response.status_code == 403: eclass = HydrusExceptions.ForbiddenException elif response.status_code == 404: eclass = HydrusExceptions.NotFoundException elif response.status_code == 419: eclass = HydrusExceptions.SessionException elif response.status_code == 426: eclass = HydrusExceptions.NetworkVersionException else: eclass = HydrusExceptions.NetworkException raise eclass( error_text )
def _errbackHandleProcessingError( self, failure, request ): self._CleanUpTempFile( request ) do_yaml = True try: # the error may have occured before user agent was set up! if not request.is_hydrus_user_agent: do_yaml = False except: pass if do_yaml: default_mime = HC.APPLICATION_YAML default_encoding = lambda x: yaml.safe_dump( HydrusData.ToUnicode( x ) ) else: default_mime = HC.TEXT_HTML default_encoding = lambda x: HydrusData.ToByteString( x ) if failure.type == KeyError: response_context = ResponseContext( 403, mime = default_mime, body = default_encoding( 'It appears one or more parameters required for that request were missing:' + os.linesep + failure.getTraceback() ) ) elif failure.type == HydrusExceptions.PermissionException: response_context = ResponseContext( 401, mime = default_mime, body = default_encoding( failure.value ) ) elif failure.type == HydrusExceptions.ForbiddenException: response_context = ResponseContext( 403, mime = default_mime, body = default_encoding( failure.value ) ) elif failure.type == HydrusExceptions.NotFoundException: response_context = ResponseContext( 404, mime = default_mime, body = default_encoding( failure.value ) ) elif failure.type == HydrusExceptions.NetworkVersionException: response_context = ResponseContext( 426, mime = default_mime, body = default_encoding( failure.value ) ) elif failure.type == HydrusExceptions.ServerBusyException: response_context = ResponseContext( 503, mime = default_mime, body = default_encoding( failure.value ) ) elif failure.type == HydrusExceptions.SessionException: response_context = ResponseContext( 419, mime = default_mime, body = default_encoding( failure.value ) ) else: HydrusData.DebugPrint( failure.getTraceback() ) response_context = ResponseContext( 500, mime = default_mime, body = default_encoding( 'The repository encountered an error it could not handle! Here is a dump of what happened, which will also be written to your client.log file. If it persists, please forward it to [email protected]:' + os.linesep * 2 + failure.getTraceback() ) ) request.hydrus_response_context = response_context return request
def wx_code(job_key): try: result = callable(*args, **kwargs) job_key.SetVariable('result', result) except HydrusExceptions.PermissionException as e: job_key.SetVariable('error', e) except Exception as e: job_key.SetVariable('error', e) HydrusData.Print('CallBlockingToWx just caught this error:') HydrusData.DebugPrint(traceback.format_exc()) finally: job_key.Finish()
def _errbackHandleEmergencyError( self, failure, request ): try: self._CleanUpTempFile( request ) except: pass try: HydrusData.DebugPrint( failure.getTraceback() ) except: pass if request.channel is not None: try: request.setResponseCode( 500 ) except: pass try: request.write( failure.getTraceback() ) except: pass if not request.finished: try: request.finish() except: pass
def CatchExceptionClient(etype, value, tb): try: trace_list = traceback.format_tb(tb) trace = ''.join(trace_list) pretty_value = HydrusData.ToUnicode(value) if os.linesep in pretty_value: (first_line, anything_else) = pretty_value.split(os.linesep, 1) trace = trace + os.linesep + anything_else else: first_line = pretty_value trace = HydrusData.ToUnicode(trace) job_key = ClientThreading.JobKey() if etype == HydrusExceptions.ShutdownException: return else: try: job_key.SetVariable('popup_title', HydrusData.ToUnicode(etype.__name__)) except: job_key.SetVariable('popup_title', HydrusData.ToUnicode(etype)) job_key.SetVariable('popup_text_1', first_line) job_key.SetVariable('popup_traceback', trace) text = job_key.ToString() HydrusData.Print('Uncaught exception:') HydrusData.DebugPrint(text) HG.client_controller.pub('message', job_key) except: text = 'Encountered an error I could not parse:' text += os.linesep text += HydrusData.ToUnicode((etype, value, tb)) try: text += traceback.format_exc() except: pass HydrusData.ShowText(text) time.sleep(1)
def ConvertStatusCodeAndDataIntoExceptionInfo(status_code, data, is_hydrus_service=False): error_text = data if len(error_text) > 1024: large_chunk = error_text[:4096] smaller_chunk = large_chunk[:256] HydrusData.DebugPrint(large_chunk) error_text = 'The server\'s error text was too long to display. The first part follows, while a larger chunk has been written to the log.' error_text += os.linesep error_text += smaller_chunk if status_code == 304: eclass = HydrusExceptions.NotModifiedException elif status_code == 401: eclass = HydrusExceptions.PermissionException elif status_code == 403: eclass = HydrusExceptions.ForbiddenException elif status_code == 404: eclass = HydrusExceptions.NotFoundException elif status_code == 419: eclass = HydrusExceptions.SessionException elif status_code == 426: eclass = HydrusExceptions.NetworkVersionException elif status_code == 509: eclass = HydrusExceptions.BandwidthException elif status_code >= 500: if is_hydrus_service and status_code == 503: eclass = HydrusExceptions.ServerBusyException else: eclass = HydrusExceptions.ServerException else: eclass = HydrusExceptions.NetworkException e = eclass(error_text) return (e, error_text)
def Exit(self): if HG.emergency_exit: self.ShutdownView() self.ShutdownModel() HydrusData.CleanRunningFile(self.db_dir, 'client') else: try: last_shutdown_work_time = self.Read('last_shutdown_work_time') shutdown_work_period = self.new_options.GetInteger( 'shutdown_work_period') we_can_shutdown_work = HydrusData.TimeHasPassed( last_shutdown_work_time + shutdown_work_period) idle_shutdown_action = self.options['idle_shutdown'] if we_can_shutdown_work and idle_shutdown_action in ( CC.IDLE_ON_SHUTDOWN, CC.IDLE_ON_SHUTDOWN_ASK_FIRST): idle_shutdown_max_minutes = self.options[ 'idle_shutdown_max_minutes'] time_to_stop = HydrusData.GetNow() + ( idle_shutdown_max_minutes * 60) work_to_do = self.GetIdleShutdownWorkDue(time_to_stop) if len(work_to_do) > 0: if idle_shutdown_action == CC.IDLE_ON_SHUTDOWN_ASK_FIRST: text = 'Is now a good time for the client to do up to ' + HydrusData.ToHumanInt( idle_shutdown_max_minutes ) + ' minutes\' maintenance work? (Will auto-no in 15 seconds)' text += os.linesep * 2 text += 'The outstanding jobs appear to be:' text += os.linesep * 2 text += os.linesep.join(work_to_do) with ClientGUIDialogs.DialogYesNo( self._splash, text, title='Maintenance is due') as dlg_yn: job = self.CallLaterWXSafe( dlg_yn, 15, dlg_yn.EndModal, wx.ID_NO) try: if dlg_yn.ShowModal() == wx.ID_YES: HG.do_idle_shutdown_work = True else: self.Write('last_shutdown_work_time', HydrusData.GetNow()) finally: job.Cancel() else: HG.do_idle_shutdown_work = True self.CallToThreadLongRunning(self.THREADExitEverything) except: self._DestroySplash() HydrusData.DebugPrint(traceback.format_exc()) HG.emergency_exit = True self.Exit()
def _InitDBCursor(self): self._CloseDBCursor() db_path = os.path.join(self._db_dir, self._db_filenames['main']) db_just_created = not os.path.exists(db_path) self._db = sqlite3.connect(db_path, isolation_level=None, detect_types=sqlite3.PARSE_DECLTYPES) self._connection_timestamp = HydrusData.GetNow() self._c = self._db.cursor() self._c.execute('PRAGMA temp_store = 2;') self._c.execute('PRAGMA main.cache_size = -10000;') self._c.execute('ATTACH ":memory:" AS mem;') self._AttachExternalDatabases() db_names = [ name for (index, name, path) in self._c.execute('PRAGMA database_list;') if name not in ('mem', 'temp') ] for db_name in db_names: self._c.execute('PRAGMA ' + db_name + '.cache_size = -10000;') if self._no_wal: self._c.execute('PRAGMA ' + db_name + '.journal_mode = TRUNCATE;') self._c.execute('PRAGMA ' + db_name + '.synchronous = 2;') self._c.execute('SELECT * FROM ' + db_name + '.sqlite_master;').fetchone() else: self._c.execute('PRAGMA ' + db_name + '.journal_mode = WAL;') # if this is set to 1, transactions are not immediately synced to the journal and can be undone following a power-loss # if set to 2, all transactions are synced # either way, transactions are atomically consistent, but let's not mess around when power-cut during heavy file import or w/e self._c.execute('PRAGMA ' + db_name + '.synchronous = 2;') try: self._c.execute('SELECT * FROM ' + db_name + '.sqlite_master;').fetchone() except sqlite3.OperationalError: HydrusData.DebugPrint(traceback.format_exc()) def create_no_wal_file(): HG.controller.CreateNoWALFile() self._no_wal = True if db_just_created: del self._c del self._db os.remove(db_path) create_no_wal_file() self._InitDBCursor() else: self._c.execute('PRAGMA ' + db_name + '.journal_mode = TRUNCATE;') self._c.execute('PRAGMA ' + db_name + '.synchronous = 2;') self._c.execute('SELECT * FROM ' + db_name + '.sqlite_master;').fetchone() create_no_wal_file() try: self._BeginImmediate() except Exception as e: raise HydrusExceptions.DBAccessException(HydrusData.ToUnicode(e))
def _InitDBCursor(self): self._CloseDBCursor() db_path = os.path.join(self._db_dir, self._db_filenames['main']) db_just_created = not os.path.exists(db_path) self._db = sqlite3.connect(db_path, isolation_level=None, detect_types=sqlite3.PARSE_DECLTYPES) self._connection_timestamp = HydrusData.GetNow() self._c = self._db.cursor() self._c.execute('PRAGMA main.cache_size = -10000;') self._c.execute('ATTACH ":memory:" AS mem;') self._AttachExternalDatabases() db_names = [ name for (index, name, path) in self._c.execute('PRAGMA database_list;') if name not in ('mem', 'temp') ] for db_name in db_names: self._c.execute('PRAGMA ' + db_name + '.cache_size = -10000;') if self._no_wal: self._c.execute('PRAGMA ' + db_name + '.journal_mode = TRUNCATE;') self._c.execute('PRAGMA ' + db_name + '.synchronous = 2;') self._c.execute('SELECT * FROM ' + db_name + '.sqlite_master;').fetchone() else: self._c.execute('PRAGMA ' + db_name + '.journal_mode = WAL;') self._c.execute('PRAGMA ' + db_name + '.synchronous = 1;') try: self._c.execute('SELECT * FROM ' + db_name + '.sqlite_master;').fetchone() except sqlite3.OperationalError: HydrusData.DebugPrint(traceback.format_exc()) def create_no_wal_file(): HydrusGlobals.controller.CreateNoWALFile() self._no_wal = True if db_just_created: del self._c del self._db os.remove(db_path) create_no_wal_file() self._InitDBCursor() else: self._c.execute('PRAGMA ' + db_name + '.journal_mode = TRUNCATE;') self._c.execute('PRAGMA ' + db_name + '.synchronous = 2;') self._c.execute('SELECT * FROM ' + db_name + '.sqlite_master;').fetchone() create_no_wal_file()