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
2015-08-26 21:18:39 +00:00
def StartFileQuery ( self , query_key , search_context ) :
self . CallToThread ( self . THREADDoFileQuery , query_key , search_context )
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
2013-08-28 21:31:52 +00:00
def THREADDoFileQuery ( self , query_key , search_context ) :
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
2015-03-04 22:44:32 +00:00
if query_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
2015-08-26 21:18:39 +00:00
self . pub ( ' set_num_query_results ' , 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 ( )
2015-08-26 21:18:39 +00:00
self . pub ( ' file_query_done ' , query_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