X-Git-Url: http://git.maemo.org/git/?p=theonering;a=blobdiff_plain;f=hand_tests%2Fdbus_signals.py;h=33716798f4c0278e777fb454a766f2beae3aef11;hp=512d19bf01f54ec11ddc1d7ee5809d2d90212a3f;hb=b1564246eeb9d052854c119f19b603414b780e84;hpb=0a896168838ce192cc93ef513f0cc43560f71c4f diff --git a/hand_tests/dbus_signals.py b/hand_tests/dbus_signals.py index 512d19b..3371679 100755 --- a/hand_tests/dbus_signals.py +++ b/hand_tests/dbus_signals.py @@ -1,46 +1,46 @@ #!/usr/bin/env python +import sys +sys.path.insert(0,"../src") +import logging +import pprint + import gobject import dbus import dbus.mainloop.glib import telepathy +import util.go_utils as gobject_utils +import gtk_toolbox + +_moduleLogger = logging.getLogger("receptionist") DBUS_PROPERTIES = 'org.freedesktop.DBus.Properties' -class AutoAcceptAttempt(object): +class AutoAcceptCall(object): - def __init__(self, bus, chan): + def __init__(self, bus, conn, chan, on_success, on_error): self._sessionBus = bus + self._conn = conn self._chan = chan + self._outstandingRequests = [] + self._on_success = on_success + self._on_error = on_error - self._selfHandle = None self._initiatorHandle = None self._initiatorID = None self._targetHandle = None self._targetID = None + self._requested = None self._pendingHandles = None - if False: - # @bug Unsure why this isn't working - self._chan[DBUS_PROPERTIES].Get( - telepathy.interfaces.CONNECTION_INTERFACE, - 'SelfHandle', - reply_handler = self._on_got_self_handle, - error_handler = self._on_nothing, - ) - else: - self._chan[telepathy.interfaces.CHANNEL_INTERFACE_GROUP].GetSelfHandle( - reply_handler = self._on_got_self_handle, - error_handler = self._on_nothing, - ) - self._chan[DBUS_PROPERTIES].GetAll( telepathy.interfaces.CHANNEL_INTERFACE, reply_handler = self._on_got_all, - error_handler = self._on_nothing, + error_handler = self._custom_error(self._on_got_all), ) + self._outstandingRequests.append(self._on_got_all) if False: # @bug Unsure why this isn't working @@ -48,66 +48,193 @@ class AutoAcceptAttempt(object): telepathy.interfaces.CHANNEL_INTERFACE_GROUP, 'LocalPendingMembers', reply_handler = self._on_got_pending_members, - error_handler = self._on_nothing, + error_handler = self._custom_error(self._on_got_pending_members), ) else: self._chan[telepathy.interfaces.CHANNEL_INTERFACE_GROUP].GetLocalPendingMembersWithInfo( reply_handler = self._on_got_pending_members, - error_handler = self._on_nothing, + error_handler = self._custom_error(self._on_got_pending_members), ) + self._outstandingRequests.append(self._on_got_pending_members) + + def is_inbound(self): + return not self._requested + isInbound = self._targetHandle == self._initiatorHandle + return isInbound + + @property + def initiator(self): + return self._initiatorID + + @property + def target(self): + return self._targetID + + def accept_call(self, on_accepted, on_error): + self._chan[telepathy.interfaces.CHANNEL_INTERFACE_GROUP].AddMembers( + self._pendingHandles, + "", + reply_handler = self._custom_on_accept(on_accepted), + error_handler = self._custom_on_accept_error(on_error), + ) + + def _custom_on_accept(self, callback): + + def on_accept(*args): + callback(self) + + return on_accept + + def _custom_on_accept_error(self, callback): + + def on_error(*args): + callback(self, *args) + + return on_error + + def _custom_error(self, action): - def _pickup_if_ready(self): - if None in ( - self._selfHandle, + def _on_error(*args): + _moduleLogger.error("Failed for %r (%r)" % (action, args)) + self._outstandingRequests.remove(action) + if self._outstandingRequests: + return + + self._on_error(self) + + return _on_error + + def _report_callback_done(self, action): + _moduleLogger.debug("Succeded with %r" % (action, )) + self._outstandingRequests.remove(action) + if self._outstandingRequests: + return + + assert None not in ( self._initiatorHandle, self._initiatorID, self._targetHandle, self._targetID, self._pendingHandles, - ): - # Note ready yet, still some outstanding requests - return - - if self._selfHandle != self._targetHandle: - # Turns out it was an inbound call - return - - # @bug does not distinguish between who the call is from for use for TOR auto-pickup - self._chan[telepathy.interfaces.CHANNEL_INTERFACE_GROUP].AddMembers( - reply_handler = self._on_members_added, - error_handler = self._on_nothing, + self._requested, ) - def _on_got_self_handle(self, selfHandle): - self._pickup_if_ready() + self._on_success(self) + @gtk_toolbox.log_exception(_moduleLogger) def _on_got_all(self, properties): self._initiatorID = properties["InitiatorID"] self._initiatorHandle = properties["InitiatorHandle"] self._targetID = properties["InitiatorID"] self._targetHandle = properties["InitiatorHandle"] + self._requested = properties["Requested"] - self._pickup_if_ready() + self._report_callback_done(self._on_got_all) + @gtk_toolbox.log_exception(_moduleLogger) def _on_got_pending_members(self, pendings): for pendingHandle, instigatorHandle, reason, message in pendings: print pendingHandle, instigatorHandle, reason, message self._pendingHandles = [pendingWithInfo[0] for pendingWithInfo in pendings] - self._pickup_if_ready() - def _on_members_added(self): - print "Should be picked up now" + self._report_callback_done(self._on_got_pending_members) - def _on_nothing(*args): - print "ERROR", args +class WasMissedCall(object): -class AutoAcceptCall(object): + def __init__(self, bus, conn, chan, on_success, on_error): + self._on_success = on_success + self._on_error = on_error - def __init__(self): + self._requested = None + self._didMembersChange = False + self._didClose = False + self._didReport = False + + self._timeoutId = gobject_utils.timeout_add_seconds(10, self._on_timeout) + + chan[telepathy.interfaces.CHANNEL_INTERFACE_GROUP].connect_to_signal( + "MembersChanged", + self._on_members_changed, + ) + + chan[telepathy.interfaces.CHANNEL].connect_to_signal( + "Closed", + self._on_closed, + ) + + chan[DBUS_PROPERTIES].GetAll( + telepathy.interfaces.CHANNEL_INTERFACE, + reply_handler = self._on_got_all, + error_handler = self._on_got_all, + ) + + def cancel(self): + self._report_error("by request") + + def _report_missed_if_ready(self): + if self._didReport: + pass + elif self._requested is not None and (self._didMembersChange or self._didClose): + if self._requested: + self._report_error("wrong direction") + elif self._didClose: + self._report_success() + else: + self._report_error("members added") + else: + if self._didClose: + self._report_error("closed too early") + + def _report_success(self): + assert not self._didReport + self._didReport = True + if self._timeoutId: + gobject.source_remove(self._timeoutId) + self._timeoutId = None + self._on_success(self) + + def _report_error(self, reason): + assert not self._didReport + self._didReport = True + if self._timeoutId: + gobject.source_remove(self._timeoutId) + self._timeoutId = None + self._on_error(self, reason) + + @gtk_toolbox.log_exception(_moduleLogger) + def _on_got_all(self, properties): + self._requested = properties["Requested"] + self._report_missed_if_ready() + + @gtk_toolbox.log_exception(_moduleLogger) + def _on_members_changed(self, message, added, removed, lp, rp, actor, reason): + pprint.pprint((message, added, removed, lp, rp, actor, reason)) + if added: + self._didMembersChange = True + self._report_missed_if_ready() + + @gtk_toolbox.log_exception(_moduleLogger) + def _on_closed(self): + self._didClose = True + self._report_missed_if_ready() + + @gtk_toolbox.log_exception(_moduleLogger) + def _on_error(self, *args): + self._report_error(args) + + @gtk_toolbox.log_exception(_moduleLogger) + def _on_timeout(self): + self._report_error("timeout") + return False + + +class NewChannelSignaller(object): + + def __init__(self, on_new_channel): self._sessionBus = dbus.SessionBus() - self._activeAttempts = [] + self._on_user_new_channel = on_new_channel def start(self): self._sessionBus.add_signal_receiver( @@ -118,27 +245,104 @@ class AutoAcceptCall(object): None ) - def _on_new_channel(self, channelObjectPath, channelType, handleType, handle, supressHandler): + def stop(self): + self._sessionBus.remove_signal_receiver( + self._on_new_channel, + "NewChannel", + "org.freedesktop.Telepathy.Connection", + None, + None + ) + + @gtk_toolbox.log_exception(_moduleLogger) + def _on_new_channel( + self, channelObjectPath, channelType, handleType, handle, supressHandler + ): + connObjectPath = channelObjectPath.rsplit("/", 1)[0] + serviceName = connObjectPath[1:].replace("/", ".") + conn = telepathy.client.Connection(serviceName, connObjectPath) + chan = telepathy.client.Channel(serviceName, channelObjectPath) + self._on_user_new_channel(self._sessionBus, conn, chan, channelType) + + +class AutoAcceptManager(object): + + def __init__(self): + self._newChannelSignaller = NewChannelSignaller(self._on_new_channel) + + def start(self): + self._newChannelSignaller.start() + + @gtk_toolbox.log_exception(_moduleLogger) + def _on_new_channel(self, bus, conn, chan, channelType): + pprint.pprint((bus, conn, chan, channelType)) if channelType != telepathy.interfaces.CHANNEL_TYPE_STREAMED_MEDIA: return - serviceName = channelObjectPath.rsplit("/", 1)[0][1:].replace("/", ".") - chan = telepathy.client.Channel(serviceName, channelObjectPath) - # @bug does not distinguish between preferred CMs - # @todo Need a way to be notified on error, ignored, or if picked up - attemptPickup = AutoAcceptAttempt(self._sessionBus, chan) - self._activeAttempts.append(attemptPickup) + # @todo distinguish between preferred CMs + attemptPickup = AutoAcceptCall(bus, conn, chan, self._on_inbound_call, self._on_inbound_call_error) + + @gtk_toolbox.log_exception(_moduleLogger) + def _on_inbound_call(self, autoAcceptCall): + # @todo Add a comparison for picking up for only certain contacts + print autoAcceptCall.initiator, autoAcceptCall.target + if autoAcceptCall.is_inbound(): + autoAcceptCall.accept_call(self._on_call_pickedup, self._on_pickup_error) + else: + _moduleLogger.debug( + "Not an inbound call (initiator=%r, target=%r)" % (autoAcceptCall.initiator, autoAcceptCall.target) + ) + + @gtk_toolbox.log_exception(_moduleLogger) + def _on_inbound_call_error(self, *args): + _moduleLogger.info("Inbound call error") + + @gtk_toolbox.log_exception(_moduleLogger) + def _on_call_pickedup(self, autoAcceptCall): + _moduleLogger.info("Call picked up") + + @gtk_toolbox.log_exception(_moduleLogger) + def _on_pickup_error(self, autoAcceptCall, *args): + _moduleLogger.info("Call failed to pick up (%r)" % (args, )) + + +class MissedManager(object): + + def __init__(self): + self._newChannelSignaller = NewChannelSignaller(self._on_new_channel) + + def start(self): + self._newChannelSignaller.start() + + @gtk_toolbox.log_exception(_moduleLogger) + def _on_new_channel(self, bus, conn, chan, channelType): + pprint.pprint((bus, conn, chan, channelType)) + if channelType != telepathy.interfaces.CHANNEL_TYPE_STREAMED_MEDIA: + return + + missDetection = WasMissedCall( + bus, conn, chan, self._on_missed_call, self._on_error_for_missed + ) + + @gtk_toolbox.log_exception(_moduleLogger) + def _on_missed_call(self, missDetection): + _moduleLogger.info("Missed a call") - def _on_nothing(*args): - print "ERROR", args + @gtk_toolbox.log_exception(_moduleLogger) + def _on_error_for_missed(self, missDetection, reason): + _moduleLogger.info("Error: %r claims %r" % (missDetection, reason)) if __name__ == "__main__": + logging.basicConfig(level=logging.DEBUG) l = dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) - autoaccept = AutoAcceptCall() + if False: + manager = AutoAcceptManager() + else: + manager = MissedManager() gobject.threads_init() - gobject.idle_add(autoaccept.start) + gobject.idle_add(manager.start) mainloop = gobject.MainLoop(is_running=True) mainloop.run()