[telepathy-ashes/master] Restarts okay when gabble dies.

David Laban david.laban at collabora.co.uk
Thu Nov 12 15:49:17 PST 2009


Added a callback for NameOwnerChanged. Should probably generalise
this to things other than connection, but I'm not sure how much
optimisation dbus-python does internally here.
---
 ashes/tools/bases.py            |   12 ++++++++++
 ashes/tools/echo_daemon.py      |    6 +++-
 ashes/tools/helper_functions.py |   44 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 60 insertions(+), 2 deletions(-)

diff --git a/ashes/tools/bases.py b/ashes/tools/bases.py
index 5e617ed..fadc37f 100644
--- a/ashes/tools/bases.py
+++ b/ashes/tools/bases.py
@@ -10,6 +10,7 @@ import gobject
 import dbus
 import telepathy
 
+from helper_functions import WeakCallback
 
 
 class ObjectListener(object):
@@ -25,6 +26,12 @@ class ObjectListener(object):
         self.service_name = dbus_object.service_name
         self.object_path = dbus_object.object_path
         self.signal_matches = []
+        name_owner_cb = getattr(self, 'NameOwnerChanged', None)
+        if name_owner_cb is not None:
+            cb = WeakCallback(name_owner_cb)
+            name_owner_watch = dbus.SessionBus().watch_name_owner(
+                    self.service_name, name_owner_cb)
+            cb.add_cancel_funtion(name_owner_watch.cancel)
 
     def __eq__(self, other):
         """
@@ -133,6 +140,11 @@ class ConnectionListener(ObjectListener):
         if status == 2: # Disconnected.
             self.parent.connection_disconnected(self, status, reason)
 
+    def NameOwnerChanged(self, new_owner):
+        if new_owner == "":
+            self.parent.connection_disconnected(self, 2,
+                    "invalidated: NameOwnerChanged.")
+
     # FIXME: this should really be auto-generated from the spec globally.
     _signal_names = {
         'org.freedesktop.Telepathy.Connection':
diff --git a/ashes/tools/echo_daemon.py b/ashes/tools/echo_daemon.py
index ad6b0b1..525d2e8 100644
--- a/ashes/tools/echo_daemon.py
+++ b/ashes/tools/echo_daemon.py
@@ -148,7 +148,8 @@ def do_daemon(account_file):
     # Don't go into the background until we're sure we're set up correctly.
     echobot_logfile = open("%s/log/echobot-%s-%s.log" %
                         (HOME, ACCOUNT_NAME, DATE), 'w')
-    forward_stream_until(echo_bot.stdout, echobot_logfile, "List Handled:")
+    last_line = forward_stream_until(echo_bot.stdout, echobot_logfile, "List Handled:")
+    assert "List Handled:" in last_line
     assert echo_bot.poll() is None
     # Bot is alive and set up correctly.
     # Now we can go into the background.
@@ -187,7 +188,7 @@ def do_daemon(account_file):
 def forward_stream_until(from_stream, to_stream, stop):
     """Copies data from from_stream into to_stream until stop appears in the stream"""
     assert '\n' not in stop # Can't handle things split over multiple lines easily.
-    line = 1
+    line = 'Program exited without creating any output'
     while line:
         last_line = line
         line = from_stream.readline()
@@ -195,6 +196,7 @@ def forward_stream_until(from_stream, to_stream, stop):
         to_stream.flush()
         if stop and stop in line:
             return line
+        print line,
     return last_line
 
 def forward_stream(from_stream, to_stream):
diff --git a/ashes/tools/helper_functions.py b/ashes/tools/helper_functions.py
index d7cd119..555f799 100644
--- a/ashes/tools/helper_functions.py
+++ b/ashes/tools/helper_functions.py
@@ -16,12 +16,56 @@ copying = """
     along with this program.  If not, see <http://www.gnu.org/licenses/>."""
 
 import time
+import weakref
 
 import gobject
 import dbus
 import telepathy
 import pdb
 
+class WeakCallback(object):
+    """
+    Used to wrap bound methods without keeping a ref to the underlying object.
+    You can also pass in user_data and user_kwargs in the same way as with
+    rpartial. Note that refs will be kept to everything you pass in other than
+    the callback, which will have a weakref kept to it.
+    """
+    def __init__(self, callback, *user_data, **user_kwargs):
+        self.im_self = weakref.proxy(callback.im_self, self._invalidated)
+        self.im_func = weakref.proxy(callback.im_func)
+        self.user_data = user_data
+        self.user_kwargs = user_kwargs
+
+    def __call__(self, *args, **kwargs):
+        kwargs.update(self.user_kwargs)
+        args += self.user_data
+        self.im_func(self.im_self, *args, **kwargs)
+
+    def _invalidated(self, im_self):
+        """Called by the weakref.proxy object."""
+        cb = getattr(self, 'cancel_callback', None)
+        if cb is not None:
+            cb()
+
+    def add_cancel_funtion(self, cancel_callback):
+        """
+        A ref will be kept to cancel_callback. It will be called back without
+        any args when the underlying object dies.
+        You can wrap it in WeakCallback if you want, but that's a bit too
+        self-referrential for me to do by default. Also, that would stop you
+        being able to use a lambda as the cancel_callback.
+        """
+        self.cancel_callback = cancel_callback
+
+def weak_connect(sender, signal, callback):
+    """
+    API-compatible with the function described in
+    http://stackoverflow.com/questions/1364923/. Mostly used as an example.
+    """
+    cb = WeakCallback(callback)
+    handle = sender.connect(signal, cb)
+    cb.add_cancel_function(WeakCallback(sender.disconnect, handle))
+
 def get_property(object, interface, name, **kwargs):
     """Use the Properties interface to get a property from an interface."""
     return object['org.freedesktop.DBus.Properties'].Get(interface, name, **kwargs)
-- 
1.5.6.5



More information about the telepathy-commits mailing list