hydrus/include/ClientController.py

288 lines
9.8 KiB
Python
Raw Normal View History

2013-02-19 00:11:43 +00:00
import gc
import HydrusConstants as HC
import HydrusImageHandling
2013-03-15 02:38:12 +00:00
import HydrusSessions
2013-02-19 00:11:43 +00:00
import ClientConstants as CC
import ClientDB
import ClientGUI
import os
2013-04-03 20:56:07 +00:00
import sqlite3
2013-02-19 00:11:43 +00:00
import threading
import time
import traceback
import wx
import wx.richtext
ID_ANIMATED_EVENT_TIMER = wx.NewId()
ID_MAINTENANCE_EVENT_TIMER = wx.NewId()
class Controller( wx.App ):
2013-05-08 20:31:00 +00:00
def _Read( self, action, *args, **kwargs ):
if action == 'options': return self._options
elif action == 'tag_service_precedence': return self._tag_service_precedence
elif action == 'file': return self._db.ReadFile( *args, **kwargs )
elif action == 'thumbnail': return self._db.ReadThumbnail( *args, **kwargs )
else: return self._db.Read( action, HC.HIGH_PRIORITY, *args, **kwargs )
def _Write( self, action, priority, *args, **kwargs ): self._db.Write( action, priority, *args, **kwargs )
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()
def Clipboard( self, type, data ):
# need this cause can't do it in a non-gui thread
if type == 'paths':
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
2013-03-23 17:57:29 +00:00
elif type == 'text':
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.' )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def DeleteSessionKey( self, service_identifier ): self._session_manager.DeleteSessionKey( service_identifier )
2013-02-19 00:11:43 +00:00
def EventAnimatedTimer( self, event ):
del gc.garbage[:]
HC.pubsub.pub( 'animated_tick' )
def EventMaintenanceTimer( self, event ):
2013-03-15 02:38:12 +00:00
if int( time.time() ) - self._last_idle_time > 60 * 60: # a long time, so we probably just woke up from a sleep
self._last_idle_time = int( time.time() )
2013-02-19 00:11:43 +00:00
if int( time.time() ) - self._last_idle_time > 20 * 60: # 20 mins since last user-initiated db request
self.MaintainDB()
def EventPubSub( self, event ):
pubsubs_queue = HC.pubsub.GetQueue()
( callable, args, kwargs ) = pubsubs_queue.get()
try: callable( *args, **kwargs )
except wx._core.PyDeadObjectError: pass
except TypeError: pass
except Exception as e:
print( type( e ) )
print( traceback.format_exc() )
pubsubs_queue.task_done()
def Exception( self, exception ): wx.MessageBox( unicode( exception ) )
def GetFullscreenImageCache( self ): return self._fullscreen_image_cache
def GetGUI( self ): return self._gui
def GetLog( self ): return self._log
def GetPreviewImageCache( self ): return self._preview_image_cache
2013-03-15 02:38:12 +00:00
def GetSessionKey( self, service_identifier ): return self._session_manager.GetSessionKey( service_identifier )
2013-05-08 20:31:00 +00:00
def GetTagSiblingsManager( self ): return self._tag_siblings_manager
2013-04-03 20:56:07 +00:00
2013-02-19 00:11:43 +00:00
def GetThumbnailCache( self ): return self._thumbnail_cache
2013-05-08 20:31:00 +00:00
def GetWebCookies( self, name ): return self._web_session_manager.GetCookies( name )
2013-02-19 00:11:43 +00:00
def MaintainDB( self ):
now = int( time.time() )
shutdown_timestamps = self.Read( 'shutdown_timestamps' )
if now - shutdown_timestamps[ CC.SHUTDOWN_TIMESTAMP_VACUUM ] > 86400 * 5: self.Write( 'vacuum' )
2013-05-08 20:31:00 +00:00
# try no fatten, since we made the recent A/C changes
#if now - shutdown_timestamps[ CC.SHUTDOWN_TIMESTAMP_FATTEN_AC_CACHE ] > 50000: self.Write( 'fatten_autocomplete_cache' )
2013-02-19 00:11:43 +00:00
if now - shutdown_timestamps[ CC.SHUTDOWN_TIMESTAMP_DELETE_ORPHANS ] > 86400 * 3: self.Write( 'delete_orphans' )
def Message( self, message ): wx.MessageBox( message )
def OnInit( self ):
try:
self._splash = ClientGUI.FrameSplash()
self.SetSplashText( 'log' )
self._log = CC.Log()
self.SetSplashText( 'db' )
self._db = ClientDB.DB()
self._options = self._db.Read( 'options', HC.HIGH_PRIORITY )
self._tag_service_precedence = self._db.Read( 'tag_service_precedence', HC.HIGH_PRIORITY )
2013-03-15 02:38:12 +00:00
self._session_manager = HydrusSessions.HydrusSessionManagerClient()
2013-04-03 20:56:07 +00:00
self._web_session_manager = CC.WebSessionManagerClient()
2013-05-08 20:31:00 +00:00
self._tag_siblings_manager = CC.TagSiblingsManager()
2013-03-15 02:38:12 +00:00
2013-02-19 00:11:43 +00:00
self.SetSplashText( 'caches' )
self._fullscreen_image_cache = CC.RenderedImageCache( self._db, self._options, 'fullscreen' )
self._preview_image_cache = CC.RenderedImageCache( self._db, self._options, 'preview' )
self._thumbnail_cache = CC.ThumbnailCache( self._db, self._options )
CC.GlobalBMPs.STATICInitialise()
self.SetSplashText( 'gui' )
self._gui = ClientGUI.FrameGUI()
HC.pubsub.sub( self, 'Exception', 'exception' )
HC.pubsub.sub( self, 'Message', 'message' )
HC.pubsub.sub( self, 'Clipboard', 'clipboard' )
self.Bind( HC.EVT_PUBSUB, self.EventPubSub )
# 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.Bind( wx.EVT_TIMER, self.EventAnimatedTimer, id = ID_ANIMATED_EVENT_TIMER )
self._animated_event_timer = wx.Timer( self, ID_ANIMATED_EVENT_TIMER )
self._animated_event_timer.Start( 1000, wx.TIMER_CONTINUOUS )
self.SetSplashText( 'starting daemons' )
2013-04-03 20:56:07 +00:00
if HC.is_first_start: self._gui.DoFirstStart()
2013-02-19 00:11:43 +00:00
self._db._InitPostGUI()
self._last_idle_time = 0.0
self.Bind( wx.EVT_TIMER, self.EventMaintenanceTimer, id = ID_MAINTENANCE_EVENT_TIMER )
self._maintenance_event_timer = wx.Timer( self, ID_MAINTENANCE_EVENT_TIMER )
self._maintenance_event_timer.Start( 20 * 60000, wx.TIMER_CONTINUOUS )
2013-04-03 20:56:07 +00:00
except sqlite3.OperationalError:
message = 'This instance of the client had a problem connecting to the database, which probably means an old instance is still closing.'
message += os.linesep + os.linesep
message += 'This instance will now close. You can either wait a while and try again, or force-close the old instance through task manager and try again immediately.'
wx.MessageBox( message )
return False
2013-02-19 00:11:43 +00:00
except HC.PermissionException as e: pass
except:
wx.MessageBox( 'Woah, bad error:' + os.linesep + os.linesep + traceback.format_exc() )
try: self._splash.Close()
except: pass
return False
self._splash.Close()
return True
def PrepStringForDisplay( self, text ):
if self._options[ 'gui_capitalisation' ]: return text
else: return text.lower()
def ProcessServerRequest( self, *args, **kwargs ): return self._db.ProcessRequest( *args, **kwargs )
2013-04-24 21:23:53 +00:00
def Read( self, action, *args, **kwargs ):
self._last_idle_time = int( time.time() )
return self._Read( action, *args, **kwargs )
def ReadDaemon( self, action, *args, **kwargs ): return self._Read( action, *args, **kwargs )
2013-02-19 00:11:43 +00:00
def SetSplashText( self, text ):
self._splash.SetText( text )
self.Yield() # this processes the event queue immediately, so the paint event can occur
def WaitUntilGoodTimeToUseGUIThread( self ):
pubsubs_queue = HC.pubsub.GetQueue()
while True:
if HC.shutdown: raise Exception( 'Client shutting down!' )
elif pubsubs_queue.qsize() == 0: return
else: time.sleep( 0.04 )
def Write( self, action, *args, **kwargs ):
self._last_idle_time = int( time.time() )
2013-04-24 21:23:53 +00:00
self._Write( action, HC.HIGH_PRIORITY, *args, **kwargs )
2013-02-19 00:11:43 +00:00
2013-04-24 21:23:53 +00:00
def WriteDaemon( self, action, *args, **kwargs ): self._Write( action, HC.LOW_PRIORITY, *args, **kwargs )
def WriteLowPriority( self, action, *args, **kwargs ): self._Write( action, HC.LOW_PRIORITY, *args, **kwargs )
2013-02-19 00:11:43 +00:00