speechd-discuss
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 2/2] Python: refactor SSIPClient to eliminate circular reference.


From: Christopher Brannon
Subject: [PATCH 2/2] Python: refactor SSIPClient to eliminate circular reference.
Date: Sat, 31 Jul 2010 08:59:04 -0500

The callback-handling portion of SSIPClient is now factored into a
class named _CallbackHandler.  _CallbackHandler implements the __call__
method, so it is callable.  An SSIPClient shares its _CallbackHandler
object with its _SSIPConnection object, so _SSIPConnection no longer
contains a reference to a bound method of SSIPClient.
The circular reference is gone.
---
 src/python/speechd/client.py |   64 ++++++++++++++++++++++++-----------------
 1 files changed, 37 insertions(+), 27 deletions(-)

diff --git a/src/python/speechd/client.py b/src/python/speechd/client.py
index 1251bbe..731b57e 100644
--- a/src/python/speechd/client.py
+++ b/src/python/speechd/client.py
@@ -383,6 +383,39 @@ class _SSIP_Connection(object):
         """
         self._callback = callback
 
+class _CallbackHandler(object):
+    """Internal object which handles callbacks."""
+
+    def __init__(self, client_id):
+        self._client_id = client_id
+        self._callbacks = {}
+        self._lock = threading.Lock()
+
+    def __call__(self, msg_id, client_id, type, **kwargs):
+        if client_id != self._client_id:
+            # TODO: does that ever happen?
+            return
+        self._lock.acquire()
+        try:
+            try:
+                callback, event_types = self._callbacks[msg_id]
+            except KeyError:
+                pass
+            else:
+                if event_types is None or type in event_types:
+                    callback(type, **kwargs)
+                if type in (CallbackType.END, CallbackType.CANCEL):
+                    del self._callbacks[msg_id]
+        finally:
+            self._lock.release()
+
+    def add_callback(self, msg_id,  callback, event_types):
+        self._lock.acquire()
+        try:
+            self._callbacks[msg_id] = (callback, event_types)
+        finally:
+            self._lock.release()
+
 class Scope(object):
     """An enumeration of valid SSIP command scopes.
 
@@ -552,8 +585,7 @@ class SSIPClient(object):
         self._conn.send_command('SET', Scope.SELF, 'CLIENT_NAME', full_name)
         code, msg, data = self._conn.send_command('HISTORY', 'GET', 
'CLIENT_ID')
         self._client_id = int(data[0])
-        self._lock = threading.Lock()
-        self._callbacks = {}
+        self._callback_handler = _CallbackHandler(self._client_id)
         self._conn.set_callback(self._callback_handler)
         for event in (CallbackType.INDEX_MARK,
                       CallbackType.BEGIN,
@@ -594,24 +626,6 @@ class SSIPClient(object):
         """Close the connection"""
         self.close()
 
-    def _callback_handler(self, msg_id, client_id, type, **kwargs):
-        if client_id != self._client_id:
-            # TODO: does that ever happen?
-            return
-        self._lock.acquire()
-        try:
-            try:
-                callback, event_types = self._callbacks[msg_id]
-            except KeyError:
-                pass
-            else:
-                if event_types is None or type in event_types:
-                    callback(type, **kwargs)
-                if type in (CallbackType.END, CallbackType.CANCEL):
-                    del self._callbacks[msg_id]
-        finally:
-            self._lock.release()
-
     def _server_spawn(self, connection_args):
         """Attempts to spawn the speech-dispatcher server."""
         # Check whether we are not connecting to a remote host
@@ -704,13 +718,9 @@ class SSIPClient(object):
         if callback:
             msg_id = int(result[2][0])
             # TODO: Here we risk, that the callback arrives earlier, than we
-            # add the item to `self._callbacks'.  Such a situation will lead to
-            # the callback being ignored.
-            self._lock.acquire()
-            try:
-                self._callbacks[msg_id] = (callback, event_types)
-            finally:
-                self._lock.release()
+            # add the item to `self._callback_handler'.  Such a situation will
+            # lead to the callback being ignored.
+            self._callback_handler.add_callback(msg_id, callback, event_types)
         return result
 
     def char(self, char):
-- 
1.7.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]