2014-04-23 20:56:12 +00:00
import collections
2013-02-19 00:11:43 +00:00
import gc
2013-11-06 18:22:07 +00:00
import hashlib
2013-09-25 20:20:10 +00:00
import httplib
2013-02-19 00:11:43 +00:00
import HydrusConstants as HC
2013-07-24 20:26:00 +00:00
import HydrusExceptions
2014-01-29 21:59:42 +00:00
import HydrusNetworking
2013-03-15 02:38:12 +00:00
import HydrusSessions
2013-09-25 20:20:10 +00:00
import HydrusServer
2013-07-17 20:56:13 +00:00
import HydrusTags
2014-05-21 21:37:35 +00:00
import HydrusThreading
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
2013-02-19 00:11:43 +00:00
import os
2013-08-28 21:31:52 +00:00
import random
import shutil
2013-04-03 20:56:07 +00:00
import sqlite3
2014-01-01 20:01:00 +00:00
import stat
2014-01-08 18:40:02 +00:00
import subprocess
2013-07-24 20:26:00 +00:00
import sys
2013-02-19 00:11:43 +00:00
import threading
import time
import traceback
import wx
import wx . richtext
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
ID_ANIMATED_EVENT_TIMER = wx . NewId ( )
ID_MAINTENANCE_EVENT_TIMER = wx . NewId ( )
2014-08-13 22:18:12 +00:00
MAINTENANCE_PERIOD = 5 * 60
2014-08-06 20:29:17 +00:00
2013-02-19 00:11:43 +00:00
class Controller ( wx . App ) :
2014-12-03 22:56:40 +00:00
def _CheckIfJustWokeFromSleep ( self ) :
last_maintenance_time = self . _timestamps [ ' last_maintenance_time ' ]
2014-12-10 22:02:39 +00:00
if last_maintenance_time == 0 : return False
2014-12-03 22:56:40 +00:00
# this tests if we probably just woke up from a sleep
if HC . GetNow ( ) - last_maintenance_time > MAINTENANCE_PERIOD + ( 5 * 60 ) : self . _just_woke_from_sleep = True
else : self . _just_woke_from_sleep = False
2013-08-14 20:21:49 +00:00
def _Read ( self , action , * args , * * kwargs ) : return self . _db . Read ( action , HC . HIGH_PRIORITY , * args , * * kwargs )
2013-05-08 20:31:00 +00:00
2013-07-31 21:26:38 +00:00
def _Write ( self , action , priority , synchronous , * args , * * kwargs ) : return self . _db . Write ( action , priority , synchronous , * args , * * kwargs )
2013-05-08 20:31:00 +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 :
path = dlg . GetPath ( )
2014-12-10 22:02:39 +00:00
text = ' Are you sure " ' + path + ' " is the correct directory? '
text + = os . linesep * 2
text + = ' Everything already in that directory will be deleted before the backup starts. '
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 )
2013-02-19 00:11:43 +00:00
def ClearCaches ( self ) :
self . _thumbnail_cache . Clear ( )
self . _fullscreen_image_cache . Clear ( )
self . _preview_image_cache . Clear ( )
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
image_container = HC . app . GetFullscreenImageCache ( ) . GetImage ( media )
def THREADWait ( ) :
# have to do this in thread, because the image rendered needs the wx event queue to render
start_time = time . time ( )
while not image_container . IsRendered ( ) :
if time . time ( ) - 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 )
def CopyToClipboard ( ) :
if wx . TheClipboard . Open ( ) :
hydrus_bmp = image_container . GetHydrusBitmap ( )
wx_bmp = hydrus_bmp . GetWxBitmap ( )
data = wx . BitmapDataObject ( wx_bmp )
wx . TheClipboard . SetData ( data )
wx . TheClipboard . Close ( )
else : wx . MessageBox ( ' I could not get permission to access the clipboard. ' )
HydrusThreading . CallToThread ( THREADWait )
2013-02-19 00:11:43 +00:00
2014-12-03 22:56:40 +00:00
def CurrentlyIdle ( self ) :
if HC . options [ ' idle_period ' ] == 0 : return False
return HC . GetNow ( ) - self . _timestamps [ ' last_user_action ' ] > HC . options [ ' idle_period ' ]
2014-02-19 22:37:23 +00:00
2013-02-19 00:11:43 +00:00
def EventPubSub ( self , event ) :
2014-06-18 21:53:48 +00:00
HC . currently_doing_pubsub = True
2013-08-28 21:31:52 +00:00
2013-11-13 21:30:38 +00:00
try : HC . pubsub . WXProcessQueueItem ( )
2014-06-18 21:53:48 +00:00
finally : HC . currently_doing_pubsub = False
2013-02-19 00:11:43 +00:00
2014-08-06 20:29:17 +00:00
def GetDB ( self ) : return self . _db
2013-02-19 00:11:43 +00:00
def GetFullscreenImageCache ( self ) : return self . _fullscreen_image_cache
def GetGUI ( self ) : return self . _gui
2014-09-03 20:26:49 +00:00
def GetManager ( self , manager_type ) : return self . _managers [ manager_type ]
2013-10-09 18:13:42 +00:00
2013-02-19 00:11:43 +00:00
def GetPreviewImageCache ( self ) : return self . _preview_image_cache
def GetThumbnailCache ( self ) : return self . _thumbnail_cache
2014-08-06 20:29:17 +00:00
def InitCheckPassword ( self ) :
while True :
with wx . PasswordEntryDialog ( None , ' Enter your password ' , ' Enter password ' ) as dlg :
if dlg . ShowModal ( ) == wx . ID_OK :
if hashlib . sha256 ( dlg . GetValue ( ) ) . digest ( ) == HC . options [ ' password ' ] : break
else : raise HydrusExceptions . PermissionException ( )
def InitDB ( self ) :
try :
def make_temp_files_deletable ( function_called , path , traceback_gumpf ) :
os . chmod ( path , stat . S_IWRITE )
2014-10-29 21:39:01 +00:00
try : function_called ( path ) # try again
except : pass
2014-08-06 20:29:17 +00:00
if os . path . exists ( HC . TEMP_DIR ) : shutil . rmtree ( HC . TEMP_DIR , onerror = make_temp_files_deletable )
except : pass
try :
if not os . path . exists ( HC . TEMP_DIR ) : os . mkdir ( HC . TEMP_DIR )
except : pass
db_initialised = False
while not db_initialised :
try :
self . _db = ClientDB . DB ( )
db_initialised = True
except HydrusExceptions . DBAccessException as e :
try : print ( HC . u ( e ) )
except : print ( repr ( HC . u ( e ) ) )
message = ' This instance of the client had a problem connecting to the database, which probably means an old instance is still closing. '
2014-09-24 21:50:07 +00:00
message + = os . linesep * 2
2014-08-06 20:29:17 +00:00
message + = ' If the old instance does not close for a _very_ long time, you can usually safely force-close it from task manager. '
2014-11-20 01:48:04 +00:00
with ClientGUIDialogs . DialogYesNo ( None , message , ' There was a problem connecting to the database. ' , yes_label = ' wait a bit, then try again ' , no_label = ' forget it ' ) as dlg :
2014-08-06 20:29:17 +00:00
if dlg . ShowModal ( ) == wx . ID_YES : time . sleep ( 3 )
else : raise HydrusExceptions . PermissionException ( )
threading . Thread ( target = self . _db . MainLoop , name = ' Database Main Loop ' ) . start ( )
def InitGUI ( self ) :
self . _managers = { }
2014-08-27 22:15:22 +00:00
self . _managers [ ' services ' ] = CC . ServicesManager ( )
2014-08-13 22:18:12 +00:00
2014-08-06 20:29:17 +00:00
self . _managers [ ' hydrus_sessions ' ] = HydrusSessions . HydrusSessionManagerClient ( )
self . _managers [ ' local_booru ' ] = CC . LocalBooruCache ( )
self . _managers [ ' tag_censorship ' ] = HydrusTags . TagCensorshipManager ( )
self . _managers [ ' tag_siblings ' ] = HydrusTags . TagSiblingsManager ( )
self . _managers [ ' tag_parents ' ] = HydrusTags . TagParentsManager ( )
self . _managers [ ' undo ' ] = CC . UndoManager ( )
self . _managers [ ' web_sessions ' ] = HydrusSessions . WebSessionManagerClient ( )
self . _fullscreen_image_cache = CC . RenderedImageCache ( ' fullscreen ' )
self . _preview_image_cache = CC . RenderedImageCache ( ' preview ' )
self . _thumbnail_cache = CC . ThumbnailCache ( )
CC . GlobalBMPs . STATICInitialise ( )
self . _gui = ClientGUI . FrameGUI ( )
HC . pubsub . sub ( self , ' Clipboard ' , ' clipboard ' )
HC . pubsub . sub ( self , ' RestartServer ' , ' restart_server ' )
HC . pubsub . sub ( self , ' RestartBooru ' , ' restart_booru ' )
self . Bind ( wx . EVT_TIMER , self . TIMEREventMaintenance , id = ID_MAINTENANCE_EVENT_TIMER )
self . _maintenance_event_timer = wx . Timer ( self , ID_MAINTENANCE_EVENT_TIMER )
self . _maintenance_event_timer . Start ( MAINTENANCE_PERIOD * 1000 , wx . TIMER_CONTINUOUS )
# 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 ( ) )
if HC . is_first_start : wx . CallAfter ( self . _gui . DoFirstStart )
if HC . is_db_updated : wx . CallLater ( 1 , HC . ShowText , ' The client has updated to version ' + HC . u ( HC . SOFTWARE_VERSION ) + ' ! ' )
self . RestartServer ( )
self . RestartBooru ( )
self . _db . StartDaemons ( )
2014-12-03 22:56:40 +00:00
def JustWokeFromSleep ( self ) :
if not self . _just_woke_from_sleep : self . _CheckIfJustWokeFromSleep ( )
return self . _just_woke_from_sleep
2014-10-29 21:39:01 +00:00
2013-02-19 00:11:43 +00:00
def MaintainDB ( self ) :
2013-07-10 20:25:57 +00:00
gc . collect ( )
2013-07-31 21:26:38 +00:00
now = HC . GetNow ( )
2013-02-19 00:11:43 +00:00
shutdown_timestamps = self . Read ( ' shutdown_timestamps ' )
2014-12-03 22:56:40 +00:00
if HC . options [ ' maintenance_vacuum_period ' ] != 0 :
if now - shutdown_timestamps [ CC . SHUTDOWN_TIMESTAMP_VACUUM ] > HC . options [ ' maintenance_vacuum_period ' ] : self . Write ( ' vacuum ' )
if HC . options [ ' maintenance_delete_orphans_period ' ] != 0 :
if now - shutdown_timestamps [ CC . SHUTDOWN_TIMESTAMP_DELETE_ORPHANS ] > HC . options [ ' maintenance_delete_orphans_period ' ] : self . Write ( ' delete_orphans ' )
2013-02-19 00:11:43 +00:00
2014-08-06 20:29:17 +00:00
if now - self . _timestamps [ ' last_service_info_cache_fatten ' ] > 60 * 20 :
HC . pubsub . pub ( ' set_splash_text ' , ' fattening service info ' )
2014-04-23 20:56:12 +00:00
2014-08-13 22:18:12 +00:00
services = self . GetManager ( ' services ' ) . GetServices ( )
2014-04-23 20:56:12 +00:00
2014-12-17 22:35:12 +00:00
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
2014-04-23 20:56:12 +00:00
2014-10-29 21:39:01 +00:00
self . _timestamps [ ' last_service_info_cache_fatten ' ] = HC . GetNow ( )
2014-08-06 20:29:17 +00:00
HC . pubsub . pub ( ' clear_closed_pages ' )
2014-04-23 20:56:12 +00:00
2013-02-19 00:11:43 +00:00
def OnInit ( self ) :
2014-10-29 21:39:01 +00:00
self . SetAssertMode ( wx . PYAPP_ASSERT_SUPPRESS )
2013-07-10 20:25:57 +00:00
HC . app = self
2014-01-29 21:59:42 +00:00
HC . http = HydrusNetworking . HTTPConnectionManager ( )
2013-07-10 20:25:57 +00:00
2014-04-23 20:56:12 +00:00
self . _timestamps = collections . defaultdict ( lambda : 0 )
self . _timestamps [ ' boot ' ] = HC . GetNow ( )
2014-10-29 21:39:01 +00:00
self . _just_woke_from_sleep = False
2013-09-25 20:20:10 +00:00
self . _local_service = None
2014-07-09 22:15:14 +00:00
self . _booru_service = None
2013-09-25 20:20:10 +00:00
2014-08-06 20:29:17 +00:00
self . Bind ( HC . EVT_PUBSUB , self . EventPubSub )
2013-11-06 18:22:07 +00:00
2013-02-19 00:11:43 +00:00
try :
2014-08-06 20:29:17 +00:00
splash = ClientGUI . FrameSplash ( ' boot ' )
2013-02-19 00:11:43 +00:00
2014-08-06 20:29:17 +00:00
return True
2013-02-19 00:11:43 +00:00
except :
2014-08-06 20:29:17 +00:00
print ( ' There was an error trying to start the splash screen! ' )
2013-02-19 00:11:43 +00:00
2014-08-06 20:29:17 +00:00
print ( traceback . format_exc ( ) )
2013-02-19 00:11:43 +00:00
2014-08-06 20:29:17 +00:00
try : wx . CallAfter ( splash . Destroy )
2014-01-22 21:11:22 +00:00
except : pass
2014-08-06 20:29:17 +00:00
return False
2013-02-19 00:11:43 +00:00
def PrepStringForDisplay ( self , text ) :
2013-08-14 20:21:49 +00:00
if HC . options [ ' gui_capitalisation ' ] : return text
2013-02-19 00:11:43 +00:00
else : return text . lower ( )
2014-08-13 22:18:12 +00:00
def Read ( self , action , * args , * * kwargs ) : return self . _Read ( action , * args , * * kwargs )
2013-04-24 21:23:53 +00:00
2013-07-31 21:26:38 +00:00
def ReadDaemon ( self , action , * args , * * kwargs ) :
result = self . _Read ( action , * args , * * kwargs )
time . sleep ( 0.1 )
return result
2013-04-24 21:23:53 +00:00
2014-08-13 22:18:12 +00:00
def ResetIdleTimer ( self ) : self . _timestamps [ ' last_user_action ' ] = HC . GetNow ( )
2014-07-09 22:15:14 +00:00
def RestartBooru ( self ) :
2014-08-27 22:15:22 +00:00
service = self . GetManager ( ' services ' ) . GetService ( HC . LOCAL_BOORU_SERVICE_KEY )
2014-07-09 22:15:14 +00:00
info = service . GetInfo ( )
port = info [ ' port ' ]
def TWISTEDRestartServer ( ) :
def StartServer ( * args , * * kwargs ) :
try :
connection = httplib . HTTPConnection ( ' 127.0.0.1 ' , port , timeout = 10 )
try :
connection . connect ( )
connection . close ( )
text = ' The client \' s booru server could not start because something was already bound to port ' + HC . u ( port ) + ' . '
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. '
wx . CallLater ( 1 , HC . ShowText , text )
except :
2014-08-27 22:15:22 +00:00
self . _booru_service = reactor . listenTCP ( port , HydrusServer . HydrusServiceBooru ( HC . LOCAL_BOORU_SERVICE_KEY , HC . LOCAL_BOORU , ' This is the local booru. ' ) )
2014-07-09 22:15:14 +00:00
connection = httplib . HTTPConnection ( ' 127.0.0.1 ' , port , timeout = 10 )
try :
connection . connect ( )
connection . close ( )
except :
text = ' Tried to bind port ' + HC . u ( port ) + ' for the local booru, but it failed. '
wx . CallLater ( 1 , HC . ShowText , text )
2014-09-24 21:50:07 +00:00
except Exception as e : wx . CallAfter ( HC . ShowException , e )
2014-07-09 22:15:14 +00:00
if self . _booru_service is None : StartServer ( )
else :
deferred = defer . maybeDeferred ( self . _booru_service . stopListening )
deferred . addCallback ( StartServer )
reactor . callFromThread ( TWISTEDRestartServer )
2013-09-25 20:20:10 +00:00
def RestartServer ( self ) :
2013-10-02 22:06:06 +00:00
port = HC . options [ ' local_port ' ]
2013-09-25 20:20:10 +00:00
def TWISTEDRestartServer ( ) :
2013-10-23 21:36:47 +00:00
def StartServer ( * args , * * kwargs ) :
2013-09-25 20:20:10 +00:00
try :
2013-10-02 22:06:06 +00:00
connection = httplib . HTTPConnection ( ' 127.0.0.1 ' , port , timeout = 10 )
2013-09-25 20:20:10 +00:00
2013-10-02 22:06:06 +00:00
try :
connection . connect ( )
connection . close ( )
2014-05-28 21:03:24 +00:00
text = ' The client \' s local server could not start because something was already bound to port ' + HC . u ( port ) + ' . '
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 file->options. '
2013-10-02 22:06:06 +00:00
2014-04-09 20:18:58 +00:00
wx . CallLater ( 1 , HC . ShowText , text )
2013-10-02 22:06:06 +00:00
except :
2014-08-27 22:15:22 +00:00
self . _local_service = reactor . listenTCP ( port , HydrusServer . HydrusServiceLocal ( HC . LOCAL_FILE_SERVICE_KEY , HC . LOCAL_FILE , ' This is the local file service. ' ) )
2013-10-02 22:06:06 +00:00
connection = httplib . HTTPConnection ( ' 127.0.0.1 ' , port , timeout = 10 )
try :
connection . connect ( )
connection . close ( )
except :
2014-07-09 22:15:14 +00:00
text = ' Tried to bind port ' + HC . u ( port ) + ' for the local server, but it failed. '
2013-10-02 22:06:06 +00:00
2014-04-09 20:18:58 +00:00
wx . CallLater ( 1 , HC . ShowText , text )
2013-10-02 22:06:06 +00:00
2014-09-24 21:50:07 +00:00
except Exception as e : wx . CallAfter ( HC . ShowException , e )
2013-09-25 20:20:10 +00:00
if self . _local_service is None : StartServer ( )
else :
2013-10-23 21:36:47 +00:00
deferred = defer . maybeDeferred ( self . _local_service . stopListening )
2013-09-25 20:20:10 +00:00
2013-10-23 21:36:47 +00:00
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 :
path = dlg . GetPath ( )
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 :
self . _gui . Hide ( )
2014-01-22 21:11:22 +00:00
self . _gui . Close ( )
2014-01-08 18:40:02 +00:00
self . _db . Shutdown ( )
2014-08-06 20:29:17 +00:00
while not self . _db . LoopIsFinished ( ) : time . sleep ( 0.1 )
2014-01-08 18:40:02 +00:00
self . _db . RestoreBackup ( path )
call_stuff = [ sys . executable ]
call_stuff . extend ( sys . argv )
2015-01-07 23:09:00 +00:00
subprocess . Popen ( call_stuff , shell = True )
2014-01-08 18:40:02 +00:00
2014-05-21 21:37:35 +00:00
def StartFileQuery ( self , query_key , search_context ) : HydrusThreading . CallToThread ( self . THREADDoFileQuery , query_key , search_context )
2013-08-28 21:31:52 +00:00
def THREADDoFileQuery ( self , query_key , search_context ) :
try :
2014-08-13 22:18:12 +00:00
query_hash_ids = self . Read ( ' file_query_ids ' , search_context )
2013-08-28 21:31:52 +00:00
query_hash_ids = list ( query_hash_ids )
random . shuffle ( query_hash_ids )
limit = search_context . GetSystemPredicates ( ) . GetLimit ( )
if limit is not None : query_hash_ids = query_hash_ids [ : limit ]
2014-08-27 22:15:22 +00:00
service_key = search_context . GetFileServiceKey ( )
2013-08-28 21:31:52 +00:00
include_current_tags = search_context . IncludeCurrentTags ( )
media_results = [ ]
include_pending_tags = search_context . IncludePendingTags ( )
i = 0
base = 256
while i < len ( query_hash_ids ) :
if query_key . IsCancelled ( ) : return
if i == 0 : ( last_i , i ) = ( 0 , base )
else : ( last_i , i ) = ( i , i + base )
sub_query_hash_ids = query_hash_ids [ last_i : i ]
2014-08-27 22:15:22 +00:00
more_media_results = self . Read ( ' media_results_from_ids ' , service_key , sub_query_hash_ids )
2013-08-28 21:31:52 +00:00
media_results . extend ( more_media_results )
HC . pubsub . pub ( ' set_num_query_results ' , len ( media_results ) , len ( query_hash_ids ) )
2014-08-13 22:18:12 +00:00
self . WaitUntilGoodTimeToUseGUIThread ( )
2013-08-28 21:31:52 +00:00
HC . pubsub . pub ( ' file_query_done ' , query_key , media_results )
except Exception as e : HC . ShowException ( e )
2014-05-28 21:03:24 +00:00
def TIMEREventMaintenance ( self , event ) :
2014-02-05 20:54:28 +00:00
2014-11-20 01:48:04 +00:00
sys . stdout . flush ( )
sys . stderr . flush ( )
2014-12-03 22:56:40 +00:00
self . _CheckIfJustWokeFromSleep ( )
2014-02-05 20:54:28 +00:00
2014-12-03 22:56:40 +00:00
self . _timestamps [ ' last_maintenance_time ' ] = HC . GetNow ( )
2014-08-06 20:29:17 +00:00
2014-10-29 21:39:01 +00:00
if not self . _just_woke_from_sleep and self . CurrentlyIdle ( ) : self . MaintainDB ( )
2014-02-05 20:54:28 +00:00
2013-02-19 00:11:43 +00:00
def WaitUntilGoodTimeToUseGUIThread ( self ) :
while True :
if HC . shutdown : raise Exception ( ' Client shutting down! ' )
2014-06-18 21:53:48 +00:00
elif HC . pubsub . NoJobsQueued ( ) and not HC . currently_doing_pubsub : return
2014-12-25 00:07:20 +00:00
else : time . sleep ( 0.00001 )
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
2013-07-31 21:26:38 +00:00
return self . _Write ( action , HC . HIGH_PRIORITY , False , * args , * * kwargs )
2013-02-19 00:11:43 +00:00
2013-08-14 20:21:49 +00:00
def WriteSynchronous ( self , action , * args , * * kwargs ) :
2013-07-31 21:26:38 +00:00
result = self . _Write ( action , HC . LOW_PRIORITY , True , * args , * * kwargs )
time . sleep ( 0.1 )
return result
2013-02-19 00:11:43 +00:00