2013-07-10 20:25:57 +00:00
|
|
|
import HydrusConstants as HC
|
2013-02-19 00:11:43 +00:00
|
|
|
import Queue
|
|
|
|
import threading
|
|
|
|
import traceback
|
|
|
|
import weakref
|
2015-03-25 22:04:19 +00:00
|
|
|
import HydrusGlobals
|
2013-02-19 00:11:43 +00:00
|
|
|
|
2014-07-23 21:21:37 +00:00
|
|
|
class HydrusPubSub( object ):
|
2013-02-19 00:11:43 +00:00
|
|
|
|
2015-08-26 21:18:39 +00:00
|
|
|
def __init__( self, controller, binding_errors_to_ignore = None ):
|
|
|
|
|
|
|
|
if binding_errors_to_ignore is None:
|
|
|
|
|
|
|
|
binding_errors_to_ignore = []
|
|
|
|
|
|
|
|
|
|
|
|
self._controller = controller
|
|
|
|
self._binding_errors_to_ignore = binding_errors_to_ignore
|
2013-02-19 00:11:43 +00:00
|
|
|
|
2013-11-13 21:30:38 +00:00
|
|
|
self._pubsubs = []
|
2013-02-19 00:11:43 +00:00
|
|
|
|
|
|
|
self._lock = threading.Lock()
|
|
|
|
|
|
|
|
self._topics_to_objects = {}
|
|
|
|
self._topics_to_method_names = {}
|
|
|
|
|
|
|
|
|
2013-11-13 21:30:38 +00:00
|
|
|
def _GetCallables( self, topic ):
|
2013-02-19 00:11:43 +00:00
|
|
|
|
2013-11-13 21:30:38 +00:00
|
|
|
callables = []
|
|
|
|
|
|
|
|
if topic in self._topics_to_objects:
|
2013-02-19 00:11:43 +00:00
|
|
|
|
2013-11-13 21:30:38 +00:00
|
|
|
try:
|
2013-02-19 00:11:43 +00:00
|
|
|
|
2013-11-13 21:30:38 +00:00
|
|
|
objects = self._topics_to_objects[ topic ]
|
|
|
|
|
|
|
|
for object in objects:
|
2013-02-19 00:11:43 +00:00
|
|
|
|
2013-11-13 21:30:38 +00:00
|
|
|
method_names = self._topics_to_method_names[ topic ]
|
2013-02-19 00:11:43 +00:00
|
|
|
|
2013-11-13 21:30:38 +00:00
|
|
|
for method_name in method_names:
|
2013-02-19 00:11:43 +00:00
|
|
|
|
2013-11-13 21:30:38 +00:00
|
|
|
if hasattr( object, method_name ):
|
2013-02-19 00:11:43 +00:00
|
|
|
|
2013-11-13 21:30:38 +00:00
|
|
|
try:
|
|
|
|
|
|
|
|
callable = getattr( object, method_name )
|
2013-02-19 00:11:43 +00:00
|
|
|
|
2013-11-13 21:30:38 +00:00
|
|
|
callables.append( callable )
|
|
|
|
|
|
|
|
except TypeError as e:
|
|
|
|
|
|
|
|
if '_wxPyDeadObject' not in str( e ): raise
|
2013-02-19 00:11:43 +00:00
|
|
|
|
2015-08-26 21:18:39 +00:00
|
|
|
except Exception as e:
|
|
|
|
|
|
|
|
if type( e ) not in self._binding_errors_to_ignore:
|
|
|
|
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
2013-02-19 00:11:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-11-13 21:30:38 +00:00
|
|
|
except: pass
|
|
|
|
|
|
|
|
|
|
|
|
return callables
|
|
|
|
|
|
|
|
|
2014-06-18 21:53:48 +00:00
|
|
|
def NoJobsQueued( self ):
|
2013-11-13 21:30:38 +00:00
|
|
|
|
|
|
|
with self._lock:
|
|
|
|
|
|
|
|
return len( self._pubsubs ) == 0
|
2013-02-19 00:11:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2015-08-26 21:18:39 +00:00
|
|
|
def Process( self ):
|
2013-11-13 21:30:38 +00:00
|
|
|
|
2015-08-26 21:18:39 +00:00
|
|
|
# only do one list of callables at a time
|
2013-11-13 21:30:38 +00:00
|
|
|
# we don't want to map a topic to its callables until the previous topic's callables have been fully executed
|
2014-08-27 22:15:22 +00:00
|
|
|
# e.g. when we start a message with a pubsub, it'll take a while (in independant thread-time) for wx to create
|
2013-11-13 21:30:38 +00:00
|
|
|
# the dialog and hence map the new callable to the topic. this was leading to messages not being updated
|
|
|
|
# because the (short) processing thread finished and entirely pubsubbed before wx had a chance to boot the
|
|
|
|
# message.
|
|
|
|
|
2015-08-26 21:18:39 +00:00
|
|
|
callables = []
|
2013-02-19 00:11:43 +00:00
|
|
|
|
|
|
|
with self._lock:
|
|
|
|
|
2015-08-26 21:18:39 +00:00
|
|
|
if len( self._pubsubs ) > 0:
|
2013-11-13 21:30:38 +00:00
|
|
|
|
|
|
|
( topic, args, kwargs ) = self._pubsubs.pop( 0 )
|
|
|
|
|
|
|
|
callables = self._GetCallables( topic )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# do this _outside_ the lock, lol
|
2015-08-26 21:18:39 +00:00
|
|
|
|
|
|
|
for callable in callables:
|
|
|
|
|
|
|
|
callable( *args, **kwargs )
|
|
|
|
|
2013-11-13 21:30:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
def pub( self, topic, *args, **kwargs ):
|
|
|
|
|
|
|
|
with self._lock:
|
|
|
|
|
2014-08-06 20:29:17 +00:00
|
|
|
self._pubsubs.append( ( topic, args, kwargs ) )
|
|
|
|
|
2015-08-26 21:18:39 +00:00
|
|
|
|
|
|
|
self._controller.NotifyPubSubs()
|
2013-02-19 00:11:43 +00:00
|
|
|
|
|
|
|
|
2015-08-26 21:18:39 +00:00
|
|
|
def pubimmediate( self, topic, *args, **kwargs ):
|
2013-02-19 00:11:43 +00:00
|
|
|
|
|
|
|
with self._lock:
|
|
|
|
|
2015-08-26 21:18:39 +00:00
|
|
|
callables = self._GetCallables( topic )
|
2013-02-19 00:11:43 +00:00
|
|
|
|
|
|
|
|
2015-08-26 21:18:39 +00:00
|
|
|
for callable in callables: callable( *args, **kwargs )
|
|
|
|
|
2013-11-13 21:30:38 +00:00
|
|
|
|
2015-08-26 21:18:39 +00:00
|
|
|
def sub( self, object, method_name, topic ):
|
2013-11-13 21:30:38 +00:00
|
|
|
|
|
|
|
with self._lock:
|
2014-06-18 21:53:48 +00:00
|
|
|
|
2015-08-26 21:18:39 +00:00
|
|
|
if topic not in self._topics_to_objects: self._topics_to_objects[ topic ] = weakref.WeakSet()
|
|
|
|
if topic not in self._topics_to_method_names: self._topics_to_method_names[ topic ] = set()
|
2013-11-13 21:30:38 +00:00
|
|
|
|
2015-08-26 21:18:39 +00:00
|
|
|
self._topics_to_objects[ topic ].add( object )
|
|
|
|
self._topics_to_method_names[ topic ].add( method_name )
|
2013-11-13 21:30:38 +00:00
|
|
|
|
|
|
|
|
2013-02-19 00:11:43 +00:00
|
|
|
|