[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