hydrus/include/ClientThreading.py

356 lines
8.8 KiB
Python

import HydrusExceptions
import Queue
import threading
import time
import traceback
import HydrusData
import HydrusGlobals as HG
import HydrusThreading
import os
import wx
class JobKey( object ):
def __init__( self, pausable = False, cancellable = False, only_when_idle = False, only_start_if_unbusy = False, stop_time = None ):
self._key = HydrusData.GenerateKey()
self._pausable = pausable
self._cancellable = cancellable
self._only_when_idle = only_when_idle
self._only_start_if_unbusy = only_start_if_unbusy
self._stop_time = stop_time
self._start_time = HydrusData.GetNow()
self._deleted = threading.Event()
self._deletion_time = None
self._begun = threading.Event()
self._done = threading.Event()
self._cancelled = threading.Event()
self._paused = threading.Event()
self._yield_pause_period = 10
self._next_yield_pause = HydrusData.GetNow() + self._yield_pause_period
self._bigger_pause_period = 100
self._next_bigger_pause = HydrusData.GetNow() + self._bigger_pause_period
self._longer_pause_period = 1000
self._next_longer_pause = HydrusData.GetNow() + self._longer_pause_period
self._urls = []
self._variable_lock = threading.Lock()
self._variables = dict()
def __eq__( self, other ): return self.__hash__() == other.__hash__()
def __hash__( self ): return self._key.__hash__()
def __ne__( self, other ): return self.__hash__() != other.__hash__()
def _CheckCancelTests( self ):
if not self._cancelled.is_set():
should_cancel = False
if HydrusThreading.IsThreadShuttingDown():
should_cancel = True
if self._only_when_idle and not HG.client_controller.CurrentlyIdle():
should_cancel = True
if self._stop_time is not None:
if HydrusData.TimeHasPassed( self._stop_time ):
should_cancel = True
if should_cancel:
self.Cancel()
if not self._deleted.is_set():
if self._deletion_time is not None:
if HydrusData.TimeHasPassed( self._deletion_time ):
self.Finish()
self._deleted.set()
def AddURL( self, url ):
with self._variable_lock:
self._urls.append( url )
def Begin( self ): self._begun.set()
def CanBegin( self ):
self._CheckCancelTests()
if self.IsCancelled():
return False
if self._only_start_if_unbusy and HG.client_controller.SystemBusy():
return False
return True
def Cancel( self, seconds = None ):
if seconds is None:
self._cancelled.set()
self.Finish()
else:
wx.CallAfter( wx.CallLater, seconds * 1000, self.Cancel )
def Delete( self, seconds = None ):
if seconds is None:
self._deletion_time = HydrusData.GetNow()
else:
self._deletion_time = HydrusData.GetNow() + seconds
def DeleteVariable( self, name ):
with self._variable_lock:
if name in self._variables: del self._variables[ name ]
time.sleep( 0.00001 )
def Finish( self, seconds = None ):
if seconds is None:
self._done.set()
else:
wx.CallAfter( wx.CallLater, seconds * 1000, self.Finish )
def GetIfHasVariable( self, name ):
with self._variable_lock:
if name in self._variables:
return self._variables[ name ]
else:
return None
def GetKey( self ):
return self._key
def GetURLs( self ):
with self._variable_lock:
return list( self._urls )
def HasVariable( self, name ):
with self._variable_lock: return name in self._variables
def IsBegun( self ):
self._CheckCancelTests()
return self._begun.is_set()
def IsCancellable( self ):
self._CheckCancelTests()
return self._cancellable and not self.IsDone()
def IsCancelled( self ):
self._CheckCancelTests()
return HydrusThreading.IsThreadShuttingDown() or self._cancelled.is_set()
def IsDeleted( self ):
self._CheckCancelTests()
return HydrusThreading.IsThreadShuttingDown() or self._deleted.is_set()
def IsDone( self ):
self._CheckCancelTests()
return HydrusThreading.IsThreadShuttingDown() or self._done.is_set()
def IsPausable( self ):
self._CheckCancelTests()
return self._pausable and not self.IsDone()
def IsPaused( self ):
self._CheckCancelTests()
return self._paused.is_set() and not self.IsDone()
def IsWorking( self ):
self._CheckCancelTests()
return self.IsBegun() and not self.IsDone()
def PausePlay( self ):
if self._paused.is_set(): self._paused.clear()
else: self._paused.set()
def SetCancellable( self, value ): self._cancellable = value
def SetPausable( self, value ): self._pausable = value
def SetVariable( self, name, value ):
with self._variable_lock: self._variables[ name ] = value
time.sleep( 0.00001 )
def TimeRunning( self ):
return HydrusData.GetNow() - self._start_time
def ToString( self ):
stuff_to_print = []
with self._variable_lock:
if 'popup_title' in self._variables: stuff_to_print.append( self._variables[ 'popup_title' ] )
if 'popup_text_1' in self._variables: stuff_to_print.append( self._variables[ 'popup_text_1' ] )
if 'popup_text_2' in self._variables: stuff_to_print.append( self._variables[ 'popup_text_2' ] )
if 'popup_traceback' in self._variables: stuff_to_print.append( self._variables[ 'popup_traceback' ] )
stuff_to_print = [ HydrusData.ToUnicode( s ) for s in stuff_to_print ]
try:
return os.linesep.join( stuff_to_print )
except:
return repr( stuff_to_print )
def WaitIfNeeded( self ):
if HydrusData.TimeHasPassed( self._next_yield_pause ):
time.sleep( 0.1 )
self._next_yield_pause = HydrusData.GetNow() + self._yield_pause_period
if HydrusData.TimeHasPassed( self._next_bigger_pause ):
time.sleep( 1 )
self._next_bigger_pause = HydrusData.GetNow() + self._bigger_pause_period
if HydrusData.TimeHasPassed( self._longer_pause_period ):
time.sleep( 10 )
self._next_longer_pause = HydrusData.GetNow() + self._longer_pause_period
i_paused = False
should_quit = False
while self.IsPaused():
i_paused = True
time.sleep( 0.1 )
if self.IsDone():
break
if self.IsCancelled():
should_quit = True
return ( i_paused, should_quit )