hydrus/include/ClientController.py

1229 lines
40 KiB
Python
Raw Normal View History

2015-03-25 22:04:19 +00:00
import ClientCaches
2015-04-01 20:44:54 +00:00
import ClientData
2015-05-20 21:31:40 +00:00
import ClientDaemons
2016-02-03 22:12:53 +00:00
import ClientDefaults
2016-11-02 21:09:14 +00:00
import ClientGUIMenus
2015-10-21 21:53:10 +00:00
import ClientNetworking
2016-02-17 22:06:47 +00:00
import ClientThreading
2013-11-06 18:22:07 +00:00
import hashlib
2015-04-01 20:44:54 +00:00
import HydrusConstants as HC
import HydrusController
import HydrusData
2013-07-24 20:26:00 +00:00
import HydrusExceptions
2017-05-10 21:33:58 +00:00
import HydrusGlobals as HG
2014-01-29 21:59:42 +00:00
import HydrusNetworking
2015-10-21 21:53:10 +00:00
import HydrusSerialisable
2014-05-21 21:37:35 +00:00
import HydrusThreading
2016-12-07 22:12:52 +00:00
import HydrusVideoHandling
2013-02-19 00:11:43 +00:00
import ClientConstants as CC
import ClientDB
import ClientGUI
2013-05-29 20:19:54 +00:00
import ClientGUIDialogs
2017-04-05 21:16:40 +00:00
import ClientGUIScrolledPanelsManagement
import ClientGUITopLevelWindows
2013-02-19 00:11:43 +00:00
import os
2015-08-19 21:48:21 +00:00
import psutil
2015-04-08 18:10:50 +00:00
import threading
2013-02-19 00:11:43 +00:00
import time
import traceback
import wx
2013-10-02 22:06:06 +00:00
from twisted.internet import reactor
2013-10-23 21:36:47 +00:00
from twisted.internet import defer
2013-02-19 00:11:43 +00:00
2015-04-01 20:44:54 +00:00
class Controller( HydrusController.HydrusController ):
2014-12-03 22:56:40 +00:00
2015-08-26 21:18:39 +00:00
pubsub_binding_errors_to_ignore = [ wx.PyDeadObjectError ]
2013-05-08 20:31:00 +00:00
2016-10-19 20:02:56 +00:00
def __init__( self, db_dir, no_daemons, no_wal ):
2015-09-16 18:11:00 +00:00
2016-08-31 19:55:14 +00:00
self._last_shutdown_was_bad = False
2017-05-10 21:33:58 +00:00
self._is_booted = False
2016-10-19 20:02:56 +00:00
HydrusController.HydrusController.__init__( self, db_dir, no_daemons, no_wal )
2015-09-16 18:11:00 +00:00
2017-03-08 23:23:12 +00:00
self._name = 'client'
2017-05-10 21:33:58 +00:00
HG.client_controller = self
2015-09-16 18:11:00 +00:00
2016-02-03 22:12:53 +00:00
# just to set up some defaults, in case some db update expects something for an odd yaml-loading reason
self._options = ClientDefaults.GetClientDefaultOptions()
2016-10-12 21:52:50 +00:00
self._new_options = ClientData.ClientOptions( self._db_dir )
2016-02-03 22:12:53 +00:00
HC.options = self._options
2015-10-28 21:29:05 +00:00
self._last_mouse_position = None
2015-11-25 22:00:57 +00:00
self._menu_open = False
2016-01-13 22:08:19 +00:00
self._previously_idle = False
2016-05-11 18:16:39 +00:00
self._idle_started = None
2015-10-28 21:29:05 +00:00
2015-09-16 18:11:00 +00:00
2015-09-02 23:16:09 +00:00
def _InitDB( self ):
2016-10-12 21:52:50 +00:00
return ClientDB.DB( self, self._db_dir, 'client', no_wal = self._no_wal )
2015-09-02 23:16:09 +00:00
2014-01-08 18:40:02 +00:00
def BackupDatabase( self ):
with wx.DirDialog( self._gui, 'Select backup location.' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
2015-11-04 22:30:28 +00:00
path = HydrusData.ToUnicode( dlg.GetPath() )
2014-01-08 18:40:02 +00:00
2014-12-10 22:02:39 +00:00
text = 'Are you sure "' + path + '" is the correct directory?'
text += os.linesep * 2
text += 'The database will be locked while the backup occurs, which may lock up your gui as well.'
2014-01-08 18:40:02 +00:00
2014-12-10 22:02:39 +00:00
with ClientGUIDialogs.DialogYesNo( self._gui, text ) as dlg_yn:
2014-01-08 18:40:02 +00:00
if dlg_yn.ShowModal() == wx.ID_YES:
self.Write( 'backup', path )
2017-01-25 22:56:55 +00:00
def CallBlockingToWx( self, func, *args, **kwargs ):
2015-08-26 21:18:39 +00:00
def wx_code( job_key ):
try:
2017-01-25 22:56:55 +00:00
result = func( *args, **kwargs )
2015-08-26 21:18:39 +00:00
job_key.SetVariable( 'result', result )
2015-12-23 22:51:04 +00:00
except HydrusExceptions.PermissionException as e:
job_key.SetVariable( 'error', e )
2015-08-26 21:18:39 +00:00
except Exception as e:
job_key.SetVariable( 'error', e )
2015-11-18 22:44:07 +00:00
HydrusData.Print( 'CallBlockingToWx just caught this error:' )
2015-09-02 23:16:09 +00:00
HydrusData.DebugPrint( traceback.format_exc() )
2016-07-06 21:13:15 +00:00
finally:
job_key.Finish()
2015-08-26 21:18:39 +00:00
2016-02-17 22:06:47 +00:00
job_key = ClientThreading.JobKey()
2015-08-26 21:18:39 +00:00
job_key.Begin()
wx.CallAfter( wx_code, job_key )
while not job_key.IsDone():
2015-11-04 22:30:28 +00:00
if self._model_shutdown:
return
2015-08-26 21:18:39 +00:00
time.sleep( 0.05 )
2016-01-06 21:17:20 +00:00
if job_key.HasVariable( 'result' ):
2016-09-28 18:48:01 +00:00
# result can be None, for wx_code that has no return variable
2016-01-06 21:17:20 +00:00
2016-09-28 18:48:01 +00:00
result = job_key.GetIfHasVariable( 'result' )
2016-01-06 21:17:20 +00:00
2016-09-28 18:48:01 +00:00
return result
2016-01-06 21:17:20 +00:00
2016-09-28 18:48:01 +00:00
error = job_key.GetIfHasVariable( 'error' )
if error is not None:
2016-01-06 21:17:20 +00:00
2016-09-28 18:48:01 +00:00
raise error
2016-01-06 21:17:20 +00:00
2015-08-26 21:18:39 +00:00
2016-09-28 18:48:01 +00:00
raise HydrusExceptions.ShutdownException()
2015-08-26 21:18:39 +00:00
2015-09-02 23:16:09 +00:00
def CheckAlreadyRunning( self ):
2016-10-12 21:52:50 +00:00
while HydrusData.IsAlreadyRunning( self._db_dir, 'client' ):
2015-09-02 23:16:09 +00:00
2015-09-23 21:21:02 +00:00
self.pub( 'splash_set_status_text', 'client already running' )
2015-09-02 23:16:09 +00:00
def wx_code():
message = 'It looks like another instance of this client is already running, so this instance cannot start.'
message += os.linesep * 2
message += 'If the old instance is closing and does not quit for a _very_ long time, it is usually safe to force-close it from task manager.'
with ClientGUIDialogs.DialogYesNo( self._splash, message, 'The client is already running.', yes_label = 'wait a bit, then try again', no_label = 'forget it' ) as dlg:
if dlg.ShowModal() != wx.ID_YES:
raise HydrusExceptions.PermissionException()
self.CallBlockingToWx( wx_code )
for i in range( 10, 0, -1 ):
2016-10-12 21:52:50 +00:00
if not HydrusData.IsAlreadyRunning( self._db_dir, 'client' ):
2015-09-02 23:16:09 +00:00
break
2015-09-23 21:21:02 +00:00
self.pub( 'splash_set_status_text', 'waiting ' + str( i ) + ' seconds' )
2015-09-02 23:16:09 +00:00
time.sleep( 1 )
2015-10-28 21:29:05 +00:00
def CheckMouseIdle( self ):
mouse_position = wx.GetMousePosition()
if self._last_mouse_position is None:
self._last_mouse_position = mouse_position
elif mouse_position != self._last_mouse_position:
2016-12-14 21:19:07 +00:00
idle_before_position_update = self.CurrentlyIdle()
2015-10-28 21:29:05 +00:00
self._timestamps[ 'last_mouse_action' ] = HydrusData.GetNow()
self._last_mouse_position = mouse_position
2016-12-14 21:19:07 +00:00
idle_after_position_update = self.CurrentlyIdle()
2015-10-28 21:29:05 +00:00
2016-12-14 21:19:07 +00:00
move_knocked_us_out_of_idle = ( not idle_before_position_update ) and idle_after_position_update
if move_knocked_us_out_of_idle:
2015-10-28 21:29:05 +00:00
self.pub( 'refresh_status' )
2014-09-03 20:26:49 +00:00
def Clipboard( self, data_type, data ):
2013-02-19 00:11:43 +00:00
# need this cause can't do it in a non-gui thread
2014-09-03 20:26:49 +00:00
if data_type == 'paths':
2013-02-19 00:11:43 +00:00
paths = data
if wx.TheClipboard.Open():
2013-03-15 02:38:12 +00:00
data = wx.DataObjectComposite()
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
file_data = wx.FileDataObject()
for path in paths: file_data.AddFile( path )
text_data = wx.TextDataObject( os.linesep.join( paths ) )
data.Add( file_data, True )
data.Add( text_data, False )
2013-02-19 00:11:43 +00:00
wx.TheClipboard.SetData( data )
wx.TheClipboard.Close()
2013-03-15 02:38:12 +00:00
else: wx.MessageBox( 'Could not get permission to access the clipboard!' )
2013-02-19 00:11:43 +00:00
2014-09-03 20:26:49 +00:00
elif data_type == 'text':
2013-03-23 17:57:29 +00:00
text = data
if wx.TheClipboard.Open():
data = wx.TextDataObject( text )
wx.TheClipboard.SetData( data )
wx.TheClipboard.Close()
else: wx.MessageBox( 'I could not get permission to access the clipboard.' )
2014-11-20 01:48:04 +00:00
elif data_type == 'bmp':
media = data
2016-09-21 19:54:04 +00:00
image_renderer = self.GetCache( 'images' ).GetImageRenderer( media )
2014-11-20 01:48:04 +00:00
def CopyToClipboard():
if wx.TheClipboard.Open():
2016-09-21 19:54:04 +00:00
wx_bmp = image_renderer.GetWXBitmap()
2014-11-20 01:48:04 +00:00
data = wx.BitmapDataObject( wx_bmp )
wx.TheClipboard.SetData( data )
wx.TheClipboard.Close()
2016-09-21 19:54:04 +00:00
else:
wx.MessageBox( 'I could not get permission to access the clipboard.' )
2014-11-20 01:48:04 +00:00
2015-08-05 18:42:35 +00:00
def THREADWait():
2016-01-20 23:57:33 +00:00
# have to do this in thread, because the image needs the wx event queue to render
2015-08-05 18:42:35 +00:00
start_time = time.time()
2016-09-21 19:54:04 +00:00
while not image_renderer.IsReady():
2015-08-05 18:42:35 +00:00
if HydrusData.TimeHasPassed( start_time + 15 ): raise Exception( 'The image did not render in fifteen seconds, so the attempt to copy it to the clipboard was abandoned.' )
time.sleep( 0.1 )
wx.CallAfter( CopyToClipboard )
2015-08-26 21:18:39 +00:00
self.CallToThread( THREADWait )
2014-11-20 01:48:04 +00:00
2013-02-19 00:11:43 +00:00
2016-01-13 22:08:19 +00:00
def CreateSplash( self ):
try:
self._splash = ClientGUI.FrameSplash( self )
except:
HydrusData.Print( 'There was an error trying to start the splash screen!' )
HydrusData.Print( traceback.format_exc() )
raise
2014-12-03 22:56:40 +00:00
def CurrentlyIdle( self ):
2017-05-10 21:33:58 +00:00
if HG.force_idle_mode:
2016-01-13 22:08:19 +00:00
2016-05-11 18:16:39 +00:00
self._idle_started = 0
2016-01-13 22:08:19 +00:00
return True
2016-02-17 22:06:47 +00:00
if not HydrusData.TimeHasPassed( self._timestamps[ 'boot' ] + 120 ):
return False
2015-12-02 22:32:18 +00:00
idle_normal = self._options[ 'idle_normal' ]
idle_period = self._options[ 'idle_period' ]
idle_mouse_period = self._options[ 'idle_mouse_period' ]
2015-10-28 21:29:05 +00:00
2015-12-02 22:32:18 +00:00
if idle_normal:
2015-08-19 21:48:21 +00:00
2016-01-13 22:08:19 +00:00
currently_idle = True
2015-12-02 22:32:18 +00:00
2016-01-13 22:08:19 +00:00
if idle_period is not None:
2015-10-28 21:29:05 +00:00
2016-01-13 22:08:19 +00:00
if not HydrusData.TimeHasPassed( self._timestamps[ 'last_user_action' ] + idle_period ):
currently_idle = False
2015-10-28 21:29:05 +00:00
2016-01-13 22:08:19 +00:00
if idle_mouse_period is not None:
2015-10-28 21:29:05 +00:00
2016-01-13 22:08:19 +00:00
if not HydrusData.TimeHasPassed( self._timestamps[ 'last_mouse_action' ] + idle_mouse_period ):
currently_idle = False
2015-10-28 21:29:05 +00:00
2015-08-19 21:48:21 +00:00
2016-01-13 22:08:19 +00:00
else:
2015-10-28 21:29:05 +00:00
2016-01-13 22:08:19 +00:00
currently_idle = False
2015-10-28 21:29:05 +00:00
2016-01-13 22:08:19 +00:00
2016-05-11 18:16:39 +00:00
turning_idle = currently_idle and not self._previously_idle
2016-01-13 22:08:19 +00:00
self._previously_idle = currently_idle
if turning_idle:
2015-10-28 21:29:05 +00:00
2016-05-11 18:16:39 +00:00
self._idle_started = HydrusData.GetNow()
2016-01-13 22:08:19 +00:00
self.pub( 'wake_daemons' )
2015-10-28 21:29:05 +00:00
2015-08-19 21:48:21 +00:00
2016-05-11 18:16:39 +00:00
if not currently_idle:
self._idle_started = None
2016-01-13 22:08:19 +00:00
return currently_idle
2015-08-26 21:18:39 +00:00
2016-05-11 18:16:39 +00:00
def CurrentlyVeryIdle( self ):
if self._idle_started is not None and HydrusData.TimeHasPassed( self._idle_started + 3600 ):
return True
return False
2015-08-26 21:18:39 +00:00
def DoHTTP( self, *args, **kwargs ): return self._http.Request( *args, **kwargs )
def DoIdleShutdownWork( self ):
stop_time = HydrusData.GetNow() + ( self._options[ 'idle_shutdown_max_minutes' ] * 60 )
2016-01-13 22:08:19 +00:00
self._client_files_manager.Rebalance( partial = False, stop_time = stop_time )
2016-05-11 18:16:39 +00:00
self.MaintainDB( stop_time = stop_time )
2015-08-26 21:18:39 +00:00
if not self._options[ 'pause_repo_sync' ]:
2015-08-19 21:48:21 +00:00
2015-08-26 21:18:39 +00:00
services = self.GetServicesManager().GetServices( HC.REPOSITORIES )
for service in services:
if HydrusData.TimeHasPassed( stop_time ):
return
2017-03-02 02:14:56 +00:00
service.SyncProcessUpdates( only_when_idle = False, stop_time = stop_time )
2015-08-26 21:18:39 +00:00
2015-08-19 21:48:21 +00:00
2014-12-03 22:56:40 +00:00
2014-02-19 22:37:23 +00:00
2015-08-26 21:18:39 +00:00
def Exit( self ):
2017-05-10 21:33:58 +00:00
if HG.emergency_exit:
2015-09-02 23:16:09 +00:00
2016-01-06 21:17:20 +00:00
self.ShutdownView()
self.ShutdownModel()
2015-09-02 23:16:09 +00:00
2016-01-06 21:17:20 +00:00
else:
2015-09-02 23:16:09 +00:00
2016-01-06 21:17:20 +00:00
try:
2016-01-13 22:08:19 +00:00
self.CreateSplash()
2016-01-06 21:17:20 +00:00
2016-01-13 22:08:19 +00:00
idle_shutdown_action = self._options[ 'idle_shutdown' ]
2016-01-06 21:17:20 +00:00
2016-01-13 22:08:19 +00:00
if idle_shutdown_action in ( CC.IDLE_ON_SHUTDOWN, CC.IDLE_ON_SHUTDOWN_ASK_FIRST ):
2016-08-10 19:04:08 +00:00
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 ):
2016-01-13 22:08:19 +00:00
if idle_shutdown_action == CC.IDLE_ON_SHUTDOWN_ASK_FIRST:
2016-08-10 19:04:08 +00:00
text = 'Is now a good time for the client to do up to ' + HydrusData.ConvertIntToPrettyString( idle_shutdown_max_minutes ) + ' minutes\' maintenance work?'
2016-01-13 22:08:19 +00:00
with ClientGUIDialogs.DialogYesNo( self._splash, text, title = 'Maintenance is due' ) as dlg_yn:
if dlg_yn.ShowModal() == wx.ID_YES:
2017-05-10 21:33:58 +00:00
HG.do_idle_shutdown_work = True
2016-01-13 22:08:19 +00:00
else:
2017-05-10 21:33:58 +00:00
HG.do_idle_shutdown_work = True
2016-01-13 22:08:19 +00:00
2016-01-06 21:17:20 +00:00
2016-01-13 22:08:19 +00:00
exit_thread = threading.Thread( target = self.THREADExitEverything, name = 'Application Exit Thread' )
2016-01-06 21:17:20 +00:00
2016-01-13 22:08:19 +00:00
exit_thread.start()
2016-01-06 21:17:20 +00:00
2016-01-13 22:08:19 +00:00
except:
2016-01-06 21:17:20 +00:00
2016-01-13 22:08:19 +00:00
self.pub( 'splash_destroy' )
2016-01-06 21:17:20 +00:00
2016-01-13 22:08:19 +00:00
HydrusData.DebugPrint( traceback.format_exc() )
2017-05-10 21:33:58 +00:00
HG.emergency_exit = True
2016-01-13 22:08:19 +00:00
self.Exit()
2016-01-06 21:17:20 +00:00
2015-08-26 21:18:39 +00:00
2013-02-19 00:11:43 +00:00
2015-06-03 21:05:13 +00:00
def ForceIdle( self ):
2017-05-10 21:33:58 +00:00
HG.force_idle_mode = not HG.force_idle_mode
2015-09-02 23:16:09 +00:00
self.pub( 'wake_daemons' )
self.pub( 'refresh_status' )
2013-02-19 00:11:43 +00:00
2017-01-25 22:56:55 +00:00
def GetApp( self ):
return self._app
2017-06-07 22:05:15 +00:00
def GetBandwidthManager( self ):
raise NotImplementedError()
2015-12-02 22:32:18 +00:00
def GetClientFilesManager( self ):
return self._client_files_manager
2015-12-09 23:16:41 +00:00
def GetClientSessionManager( self ):
return self._client_session_manager
2017-04-19 20:58:30 +00:00
def GetCommandFromShortcut( self, shortcut_names, shortcut ):
return self._shortcuts_manager.GetCommand( shortcut_names, shortcut )
2015-09-02 23:16:09 +00:00
def GetGUI( self ): return self._gui
2013-10-09 18:13:42 +00:00
2015-05-13 20:22:39 +00:00
def GetOptions( self ):
return self._options
2015-10-14 21:02:25 +00:00
def GetNewOptions( self ):
return self._new_options
2015-07-01 22:02:07 +00:00
def GetServicesManager( self ):
return self._services_manager
2016-12-14 21:19:07 +00:00
def GoodTimeToDoForegroundWork( self ):
return not self._gui.CurrentlyBusy()
2017-04-05 21:16:40 +00:00
def InitClientFilesManager( self ):
self._client_files_manager = ClientCaches.ClientFilesManager( self )
missing_locations = self._client_files_manager.GetMissing()
while len( missing_locations ) > 0:
2017-04-19 20:58:30 +00:00
with ClientGUITopLevelWindows.DialogManage( None, 'repair file system' ) as dlg:
2017-04-05 21:16:40 +00:00
panel = ClientGUIScrolledPanelsManagement.RepairFileSystemPanel( dlg, missing_locations )
dlg.SetPanel( panel )
if dlg.ShowModal() == wx.ID_OK:
self._client_files_manager = ClientCaches.ClientFilesManager( self )
missing_locations = self._client_files_manager.GetMissing()
else:
raise HydrusExceptions.PermissionException( 'File system failed, user chose to quit.' )
2015-09-02 23:16:09 +00:00
def InitModel( self ):
2014-08-06 20:29:17 +00:00
2017-03-08 23:23:12 +00:00
self.pub( 'splash_set_title_text', u'booting db\u2026' )
2014-08-06 20:29:17 +00:00
2015-10-21 21:53:10 +00:00
self._http = ClientNetworking.HTTPConnectionManager()
2015-08-26 21:18:39 +00:00
2015-09-02 23:16:09 +00:00
HydrusController.HydrusController.InitModel( self )
2015-08-26 21:18:39 +00:00
2017-05-10 21:33:58 +00:00
self._services_manager = ClientCaches.ServicesManager( self )
2015-09-02 23:16:09 +00:00
self._options = self.Read( 'options' )
2015-10-21 21:53:10 +00:00
self._new_options = self.Read( 'serialisable', HydrusSerialisable.SERIALISABLE_TYPE_CLIENT_OPTIONS )
2015-08-26 21:18:39 +00:00
2015-09-02 23:16:09 +00:00
HC.options = self._options
2015-10-21 21:53:10 +00:00
2016-12-07 22:12:52 +00:00
if self._new_options.GetBoolean( 'use_system_ffmpeg' ):
if HydrusVideoHandling.FFMPEG_PATH.startswith( HC.BIN_DIR ):
HydrusVideoHandling.FFMPEG_PATH = os.path.basename( HydrusVideoHandling.FFMPEG_PATH )
2017-04-05 21:16:40 +00:00
self.InitClientFilesManager()
2015-12-02 22:32:18 +00:00
2015-12-09 23:16:41 +00:00
self._client_session_manager = ClientCaches.HydrusSessionManager( self )
2017-04-19 20:58:30 +00:00
self._shortcuts_manager = ClientCaches.ShortcutsManager( self )
2015-11-25 22:00:57 +00:00
self._managers[ 'local_booru' ] = ClientCaches.LocalBooruCache( self )
self._managers[ 'tag_censorship' ] = ClientCaches.TagCensorshipManager( self )
self._managers[ 'tag_siblings' ] = ClientCaches.TagSiblingsManager( self )
self._managers[ 'tag_parents' ] = ClientCaches.TagParentsManager( self )
self._managers[ 'undo' ] = ClientCaches.UndoManager( self )
self._managers[ 'web_sessions' ] = ClientCaches.WebSessionManagerClient( self )
2014-08-06 20:29:17 +00:00
2015-06-10 19:40:25 +00:00
if HC.options[ 'proxy' ] is not None:
( proxytype, host, port, username, password ) = HC.options[ 'proxy' ]
2015-10-21 21:53:10 +00:00
ClientNetworking.SetProxy( proxytype, host, port, username, password )
2015-06-10 19:40:25 +00:00
2015-09-02 23:16:09 +00:00
def wx_code():
2016-08-17 20:07:22 +00:00
self._caches[ 'images' ] = ClientCaches.RenderedImageCache( self )
2015-11-25 22:00:57 +00:00
self._caches[ 'thumbnail' ] = ClientCaches.ThumbnailCache( self )
2015-09-02 23:16:09 +00:00
CC.GlobalBMPs.STATICInitialise()
2014-08-06 20:29:17 +00:00
2015-09-02 23:16:09 +00:00
self.CallBlockingToWx( wx_code )
2014-08-06 20:29:17 +00:00
2015-08-26 21:18:39 +00:00
self.sub( self, 'Clipboard', 'clipboard' )
self.sub( self, 'RestartBooru', 'restart_booru' )
2014-08-06 20:29:17 +00:00
2015-09-02 23:16:09 +00:00
def InitView( self ):
2014-08-06 20:29:17 +00:00
2015-09-02 23:16:09 +00:00
if self._options[ 'password' ] is not None:
2015-09-23 21:21:02 +00:00
self.pub( 'splash_set_status_text', 'waiting for password' )
2015-09-02 23:16:09 +00:00
def wx_code_password():
while True:
with wx.PasswordEntryDialog( self._splash, 'Enter your password', 'Enter password' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
2016-11-23 20:37:53 +00:00
# this can produce unicode with cyrillic or w/e keyboards, which hashlib can't handle
password = HydrusData.ToByteString( dlg.GetValue() )
if hashlib.sha256( password ).digest() == self._options[ 'password' ]: break
else:
raise HydrusExceptions.PermissionException( 'Bad password check' )
2015-09-02 23:16:09 +00:00
self.CallBlockingToWx( wx_code_password )
2017-03-08 23:23:12 +00:00
self.pub( 'splash_set_title_text', u'booting gui\u2026' )
2015-09-02 23:16:09 +00:00
def wx_code_gui():
2015-11-04 22:30:28 +00:00
self._gui = ClientGUI.FrameGUI( self )
2015-09-02 23:16:09 +00:00
# this is because of some bug in wx C++ that doesn't add these by default
wx.richtext.RichTextBuffer.AddHandler( wx.richtext.RichTextHTMLHandler() )
wx.richtext.RichTextBuffer.AddHandler( wx.richtext.RichTextXMLHandler() )
self.ResetIdleTimer()
self.CallBlockingToWx( wx_code_gui )
2016-08-24 18:36:56 +00:00
# ShowText will now popup as a message, as popup message manager has overwritten the hooks
2015-09-02 23:16:09 +00:00
HydrusController.HydrusController.InitView( self )
2017-03-02 02:14:56 +00:00
self._booru_port_connection = None
2014-08-06 20:29:17 +00:00
self.RestartBooru()
2016-01-20 23:57:33 +00:00
if not self._no_daemons:
self._daemons.append( HydrusThreading.DAEMONWorker( self, 'CheckMouseIdle', ClientDaemons.DAEMONCheckMouseIdle, period = 10 ) )
2017-03-08 23:23:12 +00:00
self._daemons.append( HydrusThreading.DAEMONWorker( self, 'SynchroniseAccounts', ClientDaemons.DAEMONSynchroniseAccounts, ( 'notify_unknown_accounts', ) ) )
2017-03-02 02:14:56 +00:00
self._daemons.append( HydrusThreading.DAEMONWorker( self, 'SaveDirtyObjects', ClientDaemons.DAEMONSaveDirtyObjects, ( 'important_dirt_to_clean', ), period = 30 ) )
2016-12-14 21:19:07 +00:00
self._daemons.append( HydrusThreading.DAEMONForegroundWorker( self, 'DownloadFiles', ClientDaemons.DAEMONDownloadFiles, ( 'notify_new_downloads', 'notify_new_permissions' ) ) )
self._daemons.append( HydrusThreading.DAEMONForegroundWorker( self, 'SynchroniseSubscriptions', ClientDaemons.DAEMONSynchroniseSubscriptions, ( 'notify_restart_subs_sync_daemon', 'notify_new_subscriptions' ), init_wait = 60, pre_call_wait = 3 ) )
self._daemons.append( HydrusThreading.DAEMONForegroundWorker( self, 'CheckImportFolders', ClientDaemons.DAEMONCheckImportFolders, ( 'notify_restart_import_folders_daemon', 'notify_new_import_folders' ), period = 180 ) )
self._daemons.append( HydrusThreading.DAEMONForegroundWorker( self, 'CheckExportFolders', ClientDaemons.DAEMONCheckExportFolders, ( 'notify_restart_export_folders_daemon', 'notify_new_export_folders' ), period = 180 ) )
2017-01-11 22:31:30 +00:00
self._daemons.append( HydrusThreading.DAEMONForegroundWorker( self, 'MaintainTrash', ClientDaemons.DAEMONMaintainTrash, init_wait = 120 ) )
2017-03-02 02:14:56 +00:00
self._daemons.append( HydrusThreading.DAEMONForegroundWorker( self, 'SynchroniseRepositories', ClientDaemons.DAEMONSynchroniseRepositories, ( 'notify_restart_repo_sync_daemon', 'notify_new_permissions' ), period = 4 * 3600, pre_call_wait = 1 ) )
2016-12-14 21:19:07 +00:00
self._daemons.append( HydrusThreading.DAEMONBackgroundWorker( self, 'RebalanceClientFiles', ClientDaemons.DAEMONRebalanceClientFiles, period = 3600 ) )
self._daemons.append( HydrusThreading.DAEMONBackgroundWorker( self, 'UPnP', ClientDaemons.DAEMONUPnP, ( 'notify_new_upnp_mappings', ), init_wait = 120, pre_call_wait = 6 ) )
2016-01-20 23:57:33 +00:00
2015-09-02 23:16:09 +00:00
2016-08-31 19:55:14 +00:00
if self._db.IsFirstStart():
2016-08-24 18:36:56 +00:00
message = 'Hi, this looks like the first time you have started the hydrus client.'
message += os.linesep * 2
message += 'Don\'t forget to check out the help if you haven\'t already.'
message += os.linesep * 2
2016-10-19 20:02:56 +00:00
message += 'To dismiss popup messages like this, right-click them.'
2016-08-24 18:36:56 +00:00
HydrusData.ShowText( message )
2016-08-31 19:55:14 +00:00
if self._db.IsDBUpdated():
2016-08-24 18:36:56 +00:00
HydrusData.ShowText( 'The client has updated to version ' + str( HC.SOFTWARE_VERSION ) + '!' )
2015-06-03 21:05:13 +00:00
2016-12-21 22:30:54 +00:00
for message in self._db.GetInitialMessages():
HydrusData.ShowText( message )
2014-08-06 20:29:17 +00:00
2017-05-10 21:33:58 +00:00
def IsBooted( self ):
return self._is_booted
2016-08-31 19:55:14 +00:00
def LastShutdownWasBad( self ):
return self._last_shutdown_was_bad
2016-05-11 18:16:39 +00:00
def MaintainDB( self, stop_time = None ):
2013-02-19 00:11:43 +00:00
2017-03-08 23:23:12 +00:00
if self._new_options.GetBoolean( 'maintain_similar_files_duplicate_pairs_during_idle' ):
2017-01-25 22:56:55 +00:00
phashes_stop_time = stop_time
if phashes_stop_time is None:
phashes_stop_time = HydrusData.GetNow() + 15
self.WriteInterruptable( 'maintain_similar_files_phashes', stop_time = phashes_stop_time )
tree_stop_time = stop_time
if tree_stop_time is None:
tree_stop_time = HydrusData.GetNow() + 30
self.WriteInterruptable( 'maintain_similar_files_tree', stop_time = tree_stop_time, abandon_if_other_work_to_do = True )
search_distance = self._new_options.GetInteger( 'similar_files_duplicate_pairs_search_distance' )
search_stop_time = stop_time
if search_stop_time is None:
search_stop_time = HydrusData.GetNow() + 60
self.WriteInterruptable( 'maintain_similar_files_duplicate_pairs', search_distance, stop_time = search_stop_time, abandon_if_other_work_to_do = True )
2016-01-06 21:17:20 +00:00
2017-03-29 19:39:34 +00:00
if stop_time is None or not HydrusData.TimeHasPassed( stop_time ):
self.WriteInterruptable( 'vacuum', stop_time = stop_time )
2016-01-06 21:17:20 +00:00
2017-03-29 19:39:34 +00:00
if stop_time is None or not HydrusData.TimeHasPassed( stop_time ):
self.WriteInterruptable( 'analyze', stop_time = stop_time )
2015-08-26 21:18:39 +00:00
2016-05-11 18:16:39 +00:00
if stop_time is None or not HydrusData.TimeHasPassed( stop_time ):
2015-08-26 21:18:39 +00:00
2016-05-11 18:16:39 +00:00
if HydrusData.TimeHasPassed( self._timestamps[ 'last_service_info_cache_fatten' ] + ( 60 * 20 ) ):
2014-12-17 22:35:12 +00:00
2016-05-11 18:16:39 +00:00
self.pub( 'splash_set_status_text', 'fattening service info' )
services = self.GetServicesManager().GetServices()
for service in services:
try: self.Read( 'service_info', service.GetServiceKey() )
except: pass # sometimes this breaks when a service has just been removed and the client is closing, so ignore the error
self._timestamps[ 'last_service_info_cache_fatten' ] = HydrusData.GetNow()
2014-12-17 22:35:12 +00:00
2014-08-06 20:29:17 +00:00
2015-08-26 21:18:39 +00:00
def MaintainMemory( self ):
HydrusController.HydrusController.MaintainMemory( self )
2017-05-10 21:33:58 +00:00
if HydrusData.TimeHasPassed( self._timestamps[ 'last_page_change' ] + 30 * 60 ):
self.pub( 'clear_closed_pages' )
2015-08-26 21:18:39 +00:00
self._timestamps[ 'last_page_change' ] = HydrusData.GetNow()
2017-05-10 21:33:58 +00:00
disk_cache_maintenance_mb = self._new_options.GetNoneableInteger( 'disk_cache_maintenance_mb' )
if disk_cache_maintenance_mb is not None:
2015-08-26 21:18:39 +00:00
2017-05-10 21:33:58 +00:00
if self.CurrentlyVeryIdle():
disk_cache_stop_time = HydrusData.GetNow() + 5
elif self.CurrentlyIdle():
disk_cache_stop_time = HydrusData.GetNow() + 2
else:
disk_cache_stop_time = HydrusData.GetNow() + 1
2015-08-26 21:18:39 +00:00
2017-05-10 21:33:58 +00:00
HG.client_controller.Read( 'load_into_disk_cache', stop_time = disk_cache_stop_time, caller_limit = disk_cache_maintenance_mb * 1024 * 1024 )
2015-08-26 21:18:39 +00:00
2015-11-25 22:00:57 +00:00
def MenuIsOpen( self ):
return self._menu_open
2015-08-26 21:18:39 +00:00
def NotifyPubSubs( self ):
wx.CallAfter( self.ProcessPubSub )
2014-04-23 20:56:12 +00:00
2013-02-19 00:11:43 +00:00
2017-05-03 21:33:48 +00:00
def PageCompletelyDestroyed( self, page_key ):
2015-09-16 18:11:00 +00:00
2016-02-17 22:06:47 +00:00
try:
2017-05-03 21:33:48 +00:00
return self._gui.PageCompletelyDestroyed( page_key )
2016-02-17 22:06:47 +00:00
except wx.PyDeadObjectError:
return True
2015-09-16 18:11:00 +00:00
2017-05-03 21:33:48 +00:00
def PageClosedButNotDestroyed( self, page_key ):
2015-10-07 21:56:22 +00:00
2017-05-03 21:33:48 +00:00
return self._gui.PageClosedButNotDestroyed( page_key )
2015-10-07 21:56:22 +00:00
2015-11-25 22:00:57 +00:00
def PopupMenu( self, window, menu ):
if menu.GetMenuItemCount() > 0:
self._menu_open = True
window.PopupMenu( menu )
self._menu_open = False
2016-11-02 21:09:14 +00:00
ClientGUIMenus.DestroyMenu( menu )
2015-11-25 22:00:57 +00:00
2013-02-19 00:11:43 +00:00
def PrepStringForDisplay( self, text ):
2015-05-13 20:22:39 +00:00
if self._options[ 'gui_capitalisation' ]: return text
2013-02-19 00:11:43 +00:00
else: return text.lower()
2017-03-02 02:14:56 +00:00
def RefreshServices( self ):
self._services_manager.RefreshServices()
2015-10-28 21:29:05 +00:00
def ResetIdleTimer( self ):
self._timestamps[ 'last_user_action' ] = HydrusData.GetNow()
2014-08-13 22:18:12 +00:00
2015-08-26 21:18:39 +00:00
def ResetPageChangeTimer( self ):
self._timestamps[ 'last_page_change' ] = HydrusData.GetNow()
2014-07-09 22:15:14 +00:00
def RestartBooru( self ):
2015-07-01 22:02:07 +00:00
service = self.GetServicesManager().GetService( CC.LOCAL_BOORU_SERVICE_KEY )
2014-07-09 22:15:14 +00:00
2017-03-02 02:14:56 +00:00
port = service.GetPort()
2014-07-09 22:15:14 +00:00
def TWISTEDRestartServer():
def StartServer( *args, **kwargs ):
try:
try:
2015-06-10 19:40:25 +00:00
connection = HydrusNetworking.GetLocalConnection( port )
2014-07-09 22:15:14 +00:00
connection.close()
2015-11-04 22:30:28 +00:00
text = 'The client\'s booru server could not start because something was already bound to port ' + str( port ) + '.'
2014-07-09 22:15:14 +00:00
text += os.linesep * 2
text += 'This usually means another hydrus client is already running and occupying that port. It could be a previous instantiation of this client that has yet to shut itself down.'
text += os.linesep * 2
text += 'You can change the port this client tries to host its local server on in services->manage services.'
2016-08-24 18:36:56 +00:00
HydrusData.ShowText( text )
2014-07-09 22:15:14 +00:00
except:
2016-04-06 19:52:45 +00:00
import ClientLocalServer
2017-03-02 02:14:56 +00:00
self._booru_port_connection = reactor.listenTCP( port, ClientLocalServer.HydrusServiceBooru( service ) )
2014-07-09 22:15:14 +00:00
try:
2015-06-10 19:40:25 +00:00
connection = HydrusNetworking.GetLocalConnection( port )
2014-07-09 22:15:14 +00:00
connection.close()
2015-06-10 19:40:25 +00:00
except Exception as e:
2014-07-09 22:15:14 +00:00
2015-11-04 22:30:28 +00:00
text = 'Tried to bind port ' + str( port ) + ' for the local booru, but it failed:'
2015-06-10 19:40:25 +00:00
text += os.linesep * 2
2015-11-04 22:30:28 +00:00
text += HydrusData.ToUnicode( e )
2014-07-09 22:15:14 +00:00
2016-08-24 18:36:56 +00:00
HydrusData.ShowText( text )
2014-07-09 22:15:14 +00:00
2015-06-03 21:05:13 +00:00
except Exception as e:
wx.CallAfter( HydrusData.ShowException, e )
2014-07-09 22:15:14 +00:00
2017-03-02 02:14:56 +00:00
if self._booru_port_connection is None:
2016-02-17 22:06:47 +00:00
2016-03-16 22:19:14 +00:00
if port is not None:
StartServer()
2016-02-17 22:06:47 +00:00
2013-09-25 20:20:10 +00:00
else:
2017-03-02 02:14:56 +00:00
deferred = defer.maybeDeferred( self._booru_port_connection.stopListening )
2013-09-25 20:20:10 +00:00
2016-02-17 22:06:47 +00:00
if port is not None:
deferred.addCallback( StartServer )
2013-09-25 20:20:10 +00:00
2013-10-02 22:06:06 +00:00
reactor.callFromThread( TWISTEDRestartServer )
2013-09-25 20:20:10 +00:00
2014-01-08 18:40:02 +00:00
def RestoreDatabase( self ):
with wx.DirDialog( self._gui, 'Select backup location.' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
2015-11-04 22:30:28 +00:00
path = HydrusData.ToUnicode( dlg.GetPath() )
2014-01-08 18:40:02 +00:00
2014-12-10 22:02:39 +00:00
text = 'Are you sure you want to restore a backup from "' + path + '"?'
text += os.linesep * 2
text += 'Everything in your current database will be deleted!'
text += os.linesep * 2
text += 'The gui will shut down, and then it will take a while to complete the restore. Once it is done, the client will restart.'
2014-01-08 18:40:02 +00:00
2014-12-10 22:02:39 +00:00
with ClientGUIDialogs.DialogYesNo( self._gui, text ) as dlg_yn:
2014-01-08 18:40:02 +00:00
if dlg_yn.ShowModal() == wx.ID_YES:
2015-06-17 20:01:41 +00:00
def THREADRestart():
2016-05-25 21:54:03 +00:00
wx.CallAfter( self._gui.Exit )
2015-06-17 20:01:41 +00:00
2015-12-16 22:41:06 +00:00
while not self._db.LoopIsFinished():
time.sleep( 0.1 )
2015-06-17 20:01:41 +00:00
self._db.RestoreBackup( path )
2017-05-10 21:33:58 +00:00
while not HG.shutdown_complete:
2015-12-16 22:41:06 +00:00
time.sleep( 0.1 )
2015-06-17 20:01:41 +00:00
2015-12-16 22:41:06 +00:00
HydrusData.RestartProcess()
2015-06-17 20:01:41 +00:00
2014-01-08 18:40:02 +00:00
2015-06-17 20:01:41 +00:00
restart_thread = threading.Thread( target = THREADRestart, name = 'Application Restart Thread' )
2014-01-08 18:40:02 +00:00
2015-09-02 23:16:09 +00:00
restart_thread.start()
def Run( self ):
self._app = wx.App()
2016-09-07 20:01:05 +00:00
self._app.locale = wx.Locale( wx.LANGUAGE_DEFAULT ) # Very important to init this here and keep it non garbage collected
2016-08-24 18:36:56 +00:00
# I have had this as 'suppress' before
self._app.SetAssertMode( wx.PYAPP_ASSERT_EXCEPTION )
2015-09-02 23:16:09 +00:00
2017-03-08 23:23:12 +00:00
HydrusData.Print( u'booting controller\u2026' )
2015-11-18 22:44:07 +00:00
2016-01-13 22:08:19 +00:00
self.CreateSplash()
2015-09-02 23:16:09 +00:00
boot_thread = threading.Thread( target = self.THREADBootEverything, name = 'Application Boot Thread' )
boot_thread.start()
self._app.MainLoop()
2017-03-08 23:23:12 +00:00
HydrusData.Print( u'shutting down controller\u2026' )
2015-09-02 23:16:09 +00:00
2017-03-02 02:14:56 +00:00
def SaveDirtyObjects( self ):
2017-05-10 21:33:58 +00:00
with HG.dirty_object_lock:
2017-03-02 02:14:56 +00:00
dirty_services = [ service for service in self._services_manager.GetServices() if service.IsDirty() ]
if len( dirty_services ) > 0:
self.WriteSynchronous( 'dirty_services', dirty_services )
def SetServices( self, services ):
2017-05-10 21:33:58 +00:00
with HG.dirty_object_lock:
2017-03-02 02:14:56 +00:00
self.WriteSynchronous( 'update_services', services )
self._services_manager.RefreshServices()
2015-09-02 23:16:09 +00:00
def ShutdownView( self ):
2017-05-10 21:33:58 +00:00
if not HG.emergency_exit:
2015-09-02 23:16:09 +00:00
2016-01-06 21:17:20 +00:00
self.pub( 'splash_set_status_text', 'waiting for daemons to exit' )
2015-09-02 23:16:09 +00:00
2016-01-06 21:17:20 +00:00
self._ShutdownDaemons()
2017-05-10 21:33:58 +00:00
if HG.do_idle_shutdown_work:
2015-09-02 23:16:09 +00:00
2017-03-29 19:39:34 +00:00
try:
self.DoIdleShutdownWork()
except:
ClientData.ReportShutdownException()
2015-09-02 23:16:09 +00:00
2016-01-13 22:08:19 +00:00
HydrusController.HydrusController.ShutdownView( self )
2015-09-16 18:11:00 +00:00
2014-01-08 18:40:02 +00:00
2017-06-14 21:19:11 +00:00
def StartFileQuery( self, page_key, job_key, search_context ):
2015-08-26 21:18:39 +00:00
2017-06-14 21:19:11 +00:00
self.CallToThread( self.THREADDoFileQuery, page_key, job_key, search_context )
2015-08-26 21:18:39 +00:00
def SystemBusy( self ):
2016-01-13 22:08:19 +00:00
2017-05-10 21:33:58 +00:00
if HG.force_idle_mode:
2016-01-13 22:08:19 +00:00
return False
2015-12-02 22:32:18 +00:00
max_cpu = self._options[ 'idle_cpu_max' ]
2015-08-26 21:18:39 +00:00
2015-12-02 22:32:18 +00:00
if max_cpu is None:
2015-08-26 21:18:39 +00:00
2015-12-02 22:32:18 +00:00
self._system_busy = False
2015-08-26 21:18:39 +00:00
2015-12-02 22:32:18 +00:00
else:
2015-08-26 21:18:39 +00:00
2015-12-02 22:32:18 +00:00
if HydrusData.TimeHasPassed( self._timestamps[ 'last_cpu_check' ] + 60 ):
2015-08-26 21:18:39 +00:00
2015-12-02 22:32:18 +00:00
cpu_times = psutil.cpu_percent( percpu = True )
2015-08-26 21:18:39 +00:00
2015-12-02 22:32:18 +00:00
if True in ( cpu_time > max_cpu for cpu_time in cpu_times ):
self._system_busy = True
else:
self._system_busy = False
2015-08-26 21:18:39 +00:00
2015-12-02 22:32:18 +00:00
self._timestamps[ 'last_cpu_check' ] = HydrusData.GetNow()
2015-08-26 21:18:39 +00:00
return self._system_busy
2013-08-28 21:31:52 +00:00
2016-08-10 19:04:08 +00:00
def ThereIsIdleShutdownWorkDue( self, time_to_stop ):
2015-08-26 21:18:39 +00:00
2016-08-10 19:04:08 +00:00
maintenance_due = self.Read( 'maintenance_due', time_to_stop )
2015-05-20 21:31:40 +00:00
2016-05-11 18:16:39 +00:00
if maintenance_due:
2015-08-26 21:18:39 +00:00
2016-05-11 18:16:39 +00:00
return True
2015-08-26 21:18:39 +00:00
2017-03-02 02:14:56 +00:00
services = self.GetServicesManager().GetServices( HC.REPOSITORIES )
for service in services:
2015-08-26 21:18:39 +00:00
2017-03-02 02:14:56 +00:00
if service.CanDoIdleShutdownWork():
2015-08-26 21:18:39 +00:00
2017-03-02 02:14:56 +00:00
return True
2015-08-26 21:18:39 +00:00
2015-05-20 21:31:40 +00:00
2015-08-26 21:18:39 +00:00
return False
2015-05-20 21:31:40 +00:00
2017-06-14 21:19:11 +00:00
def THREADDoFileQuery( self, page_key, job_key, search_context ):
2013-08-28 21:31:52 +00:00
2017-02-08 22:27:00 +00:00
QUERY_CHUNK_SIZE = 256
2015-03-04 22:44:32 +00:00
query_hash_ids = self.Read( 'file_query_ids', search_context )
media_results = []
2017-02-08 22:27:00 +00:00
for sub_query_hash_ids in HydrusData.SplitListIntoChunks( query_hash_ids, QUERY_CHUNK_SIZE ):
2013-08-28 21:31:52 +00:00
2017-06-14 21:19:11 +00:00
if job_key.IsCancelled():
return
2013-08-28 21:31:52 +00:00
2016-05-04 21:50:55 +00:00
more_media_results = self.Read( 'media_results_from_ids', sub_query_hash_ids )
2013-08-28 21:31:52 +00:00
2015-03-04 22:44:32 +00:00
media_results.extend( more_media_results )
2013-08-28 21:31:52 +00:00
2017-06-14 21:19:11 +00:00
self.pub( 'set_num_query_results', page_key, len( media_results ), len( query_hash_ids ) )
2013-08-28 21:31:52 +00:00
2015-08-26 21:18:39 +00:00
self.WaitUntilPubSubsEmpty()
2013-08-28 21:31:52 +00:00
2015-03-04 22:44:32 +00:00
2015-06-24 22:10:14 +00:00
search_context.SetComplete()
2017-06-14 21:19:11 +00:00
self.pub( 'file_query_done', page_key, job_key, media_results )
2013-08-28 21:31:52 +00:00
2015-04-08 18:10:50 +00:00
def THREADBootEverything( self ):
try:
2015-09-02 23:16:09 +00:00
self.CheckAlreadyRunning()
2015-04-08 18:10:50 +00:00
2016-10-12 21:52:50 +00:00
self._last_shutdown_was_bad = HydrusData.LastShutdownWasBad( self._db_dir, 'client' )
2016-08-31 19:55:14 +00:00
2016-10-12 21:52:50 +00:00
HydrusData.RecordRunningStart( self._db_dir, 'client' )
2015-04-08 18:10:50 +00:00
2015-09-02 23:16:09 +00:00
self.InitModel()
2015-05-13 20:22:39 +00:00
2015-09-02 23:16:09 +00:00
self.InitView()
2015-04-29 19:20:35 +00:00
2017-05-10 21:33:58 +00:00
self._is_booted = True
2015-09-02 23:16:09 +00:00
except HydrusExceptions.PermissionException as e:
2015-04-08 18:10:50 +00:00
2015-11-18 22:44:07 +00:00
HydrusData.Print( e )
2015-04-08 18:10:50 +00:00
2017-05-10 21:33:58 +00:00
HG.emergency_exit = True
2015-04-08 18:10:50 +00:00
2016-01-13 22:08:19 +00:00
self.Exit()
2015-04-08 18:10:50 +00:00
2016-01-13 22:08:19 +00:00
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.'
2015-09-02 23:16:09 +00:00
HydrusData.DebugPrint( text )
2015-04-08 18:10:50 +00:00
2016-10-19 20:02:56 +00:00
HydrusData.DebugPrint( traceback.format_exc() )
2016-01-13 22:08:19 +00:00
2015-06-24 22:10:14 +00:00
wx.CallAfter( wx.MessageBox, traceback.format_exc() )
2016-01-13 22:08:19 +00:00
wx.CallAfter( wx.MessageBox, text )
2017-05-10 21:33:58 +00:00
HG.emergency_exit = True
2016-01-13 22:08:19 +00:00
self.Exit()
2015-04-08 18:10:50 +00:00
finally:
2015-08-26 21:18:39 +00:00
self.pub( 'splash_destroy' )
2015-04-08 18:10:50 +00:00
def THREADExitEverything( self ):
2015-06-03 21:05:13 +00:00
2015-04-08 18:10:50 +00:00
try:
2017-03-08 23:23:12 +00:00
self.pub( 'splash_set_title_text', u'shutting down gui\u2026' )
2015-09-23 21:21:02 +00:00
2015-09-02 23:16:09 +00:00
self.ShutdownView()
2015-04-08 18:10:50 +00:00
2017-03-08 23:23:12 +00:00
self.pub( 'splash_set_title_text', u'shutting down db\u2026' )
2015-09-23 21:21:02 +00:00
2015-09-02 23:16:09 +00:00
self.ShutdownModel()
2015-04-08 18:10:50 +00:00
2016-10-12 21:52:50 +00:00
HydrusData.CleanRunningFile( self._db_dir, 'client' )
2016-06-15 18:59:44 +00:00
2016-01-06 21:17:20 +00:00
except HydrusExceptions.PermissionException: pass
except HydrusExceptions.ShutdownException: pass
2015-04-08 18:10:50 +00:00
except:
2017-03-29 19:39:34 +00:00
ClientData.ReportShutdownException()
2015-04-08 18:10:50 +00:00
finally:
2015-08-26 21:18:39 +00:00
self.pub( 'splash_destroy' )
2015-04-08 18:10:50 +00:00
2013-02-19 00:11:43 +00:00
def Write( self, action, *args, **kwargs ):
2013-12-04 22:44:16 +00:00
if action == 'content_updates': self._managers[ 'undo' ].AddCommand( 'content_updates', *args, **kwargs )
2013-07-10 20:25:57 +00:00
2015-04-01 20:44:54 +00:00
return HydrusController.HydrusController.Write( self, action, *args, **kwargs )
2013-07-31 21:26:38 +00:00
2016-12-07 22:12:52 +00:00