Async connect/disconnect. Moved everything to a new Async and Timeout which cleans...
authorEd Page <eopage@byu.net>
Fri, 12 Feb 2010 02:53:07 +0000 (20:53 -0600)
committerEd Page <eopage@byu.net>
Fri, 12 Feb 2010 02:53:07 +0000 (20:53 -0600)
23 files changed:
src/aliasing.py
src/autogv.py
src/capabilities.py
src/channel/call.py
src/channel/contact_list.py
src/channel/debug_log.py
src/channel/debug_prompt.py
src/channel/text.py
src/channel_manager.py
src/connection.py
src/connection_manager.py
src/contacts.py
src/gtk_toolbox.py [deleted file]
src/gvoice/addressbook.py
src/gvoice/conversations.py
src/gvoice/state_machine.py
src/handle.py
src/location.py
src/presence.py
src/simple_presence.py
src/util/go_utils.py
src/util/misc.py
src/util/tp_utils.py

index 96c4dc3..22fa414 100644 (file)
@@ -3,8 +3,7 @@ import logging
 import telepathy
 
 import tp
-import gtk_toolbox
-import util.misc as util_misc
+import util.misc as misc_utils
 import handle
 
 
@@ -72,7 +71,7 @@ def make_pretty(phonenumber):
        if phonenumber is None or phonenumber is "":
                return ""
 
-       phonenumber = util_misc.normalize_number(phonenumber)
+       phonenumber = misc_utils.normalize_number(phonenumber)
 
        if phonenumber[0] == "+":
                prettynumber = _make_pretty_international(phonenumber[1:])
@@ -114,16 +113,16 @@ class AliasingMixin(tp.ConnectionInterfaceAliasing):
                """
                raise NotImplementedError("Abstract function called")
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def GetAliasFlags(self):
                return 0
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def RequestAliases(self, contactHandleIds):
                _moduleLogger.debug("Called RequestAliases")
                return [self._get_alias(handleId) for handleId in contactHandleIds]
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def GetAliases(self, contactHandleIds):
                _moduleLogger.debug("Called GetAliases")
 
@@ -133,7 +132,7 @@ class AliasingMixin(tp.ConnectionInterfaceAliasing):
                )
                return idToAlias
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def SetAliases(self, aliases):
                _moduleLogger.debug("Called SetAliases")
                # first validate that no other handle types are included
@@ -144,11 +143,11 @@ class AliasingMixin(tp.ConnectionInterfaceAliasing):
                else:
                        raise telepathy.errors.PermissionDenied("No user customizable aliases")
 
-               uglyNumber = util_misc.normalize_number(alias)
+               uglyNumber = misc_utils.normalize_number(alias)
                if len(uglyNumber) == 0:
                        # Reset to the original from login if one was provided
                        uglyNumber = self.callbackNumberParameter
-               if not util_misc.is_valid_number(uglyNumber):
+               if not misc_utils.is_valid_number(uglyNumber):
                        raise telepathy.errors.InvalidArgument("Invalid phone number %r" % (uglyNumber, ))
 
                # Update callback
index d18b28b..1955e8b 100644 (file)
@@ -19,7 +19,7 @@ import constants
 import util.coroutines as coroutines
 import util.go_utils as gobject_utils
 import util.tp_utils as telepathy_utils
-import gtk_toolbox
+import util.misc as misc_utils
 
 
 _moduleLogger = logging.getLogger("autogv")
@@ -56,7 +56,7 @@ class NewGVConversations(object):
                )
                self.__callback = None
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def _on_conversations_updated(self, conv, conversationIds):
                _moduleLogger.debug("Incoming messages from: %r" % (conversationIds, ))
                for phoneNumber in conversationIds:
@@ -108,7 +108,7 @@ class RefreshVoicemail(object):
 
                self._isStarted = False
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def _on_new_channel(self, bus, serviceName, connObjectPath, channelObjectPath, channelType):
                if channelType != telepathy.interfaces.CHANNEL_TYPE_STREAMED_MEDIA:
                        return
@@ -125,13 +125,13 @@ class RefreshVoicemail(object):
                )
                self._outstandingRequests.append(missDetection)
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def _on_missed_call(self, missDetection):
                _moduleLogger.info("Missed a call")
                self._connRef().session.voicemailsStateMachine.reset_timers()
                self._outstandingRequests.remove(missDetection)
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def _on_error_for_missed(self, missDetection, reason):
                _moduleLogger.debug("Error: %r claims %r" % (missDetection, reason))
                self._outstandingRequests.remove(missDetection)
@@ -147,7 +147,7 @@ class AutoDisconnect(object):
                        self.__connection = None
 
                self.__connectionEventId = None
-               self.__delayedDisconnectEventId = None
+               self.__delayedDisconnect = gobject_utils.Timeout(self._on_delayed_disconnect)
 
        def start(self):
                if self.__connection is not None:
@@ -156,7 +156,7 @@ class AutoDisconnect(object):
        def stop(self):
                self._cancel_delayed_disconnect()
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def _on_connection_change(self, connection, event):
                """
                @note Maemo specific
@@ -168,9 +168,7 @@ class AutoDisconnect(object):
 
                if status == conic.STATUS_DISCONNECTED:
                        _moduleLogger.info("Disconnected from network, starting countdown to logoff")
-                       self.__delayedDisconnectEventId = gobject_utils.timeout_add_seconds(
-                               5, self._on_delayed_disconnect
-                       )
+                       self.__delayedDisconnect.start(seconds=5)
                elif status == conic.STATUS_CONNECTED:
                        _moduleLogger.info("Connected to network")
                        self._cancel_delayed_disconnect()
@@ -178,13 +176,10 @@ class AutoDisconnect(object):
                        _moduleLogger.info("Other status: %r" % (status, ))
 
        def _cancel_delayed_disconnect(self):
-               if self.__delayedDisconnectEventId is None:
-                       return
                _moduleLogger.info("Cancelling auto-log off")
-               gobject.source_reove(self.__delayedDisconnectEventId)
-               self.__delayedDisconnectEventId = None
+               self.__delayedDisconnect.cancel()
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def _on_delayed_disconnect(self):
                if not self.session.is_logged_in():
                        _moduleLogger.info("Received connection change event when not logged in")
@@ -193,8 +188,6 @@ class AutoDisconnect(object):
                        self._connRef().disconnect(telepathy.CONNECTION_STATUS_REASON_NETWORK_ERROR)
                except Exception:
                        _moduleLogger.exception("Error durring disconnect")
-               self.__delayedDisconnectEventId = None
-               return False
 
 
 class DisconnectOnShutdown(object):
@@ -229,7 +222,7 @@ class DisconnectOnShutdown(object):
                        pass # Either None or close was removed (in Fremantle)
                self._osso = None
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def _on_device_state_change(self, shutdown, save_unsaved_data, memory_low, system_inactivity, message, userData):
                """
                @note Hildon specific
index 34872a6..7474eb0 100644 (file)
@@ -3,7 +3,7 @@ import logging
 import telepathy
 
 import tp
-import gtk_toolbox
+import util.misc as misc_utils
 
 
 _moduleLogger = logging.getLogger('capabilities')
@@ -32,7 +32,7 @@ class CapabilitiesMixin(tp.ConnectionInterfaceCapabilities):
                """
                raise NotImplementedError("Abstract function called")
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def GetCapabilities(self, handleIds):
                ret = []
                for handleId in handleIds:
index 5ab9a0b..0999a1a 100644 (file)
@@ -5,7 +5,8 @@ import gobject
 import telepathy
 
 import tp
-import gtk_toolbox
+import util.go_utils as gobject_utils
+import util.misc as misc_utils
 
 
 _moduleLogger = logging.getLogger("channel.call")
@@ -20,7 +21,7 @@ class CallChannel(
        def __init__(self, connection, manager, props, contactHandle):
                self.__manager = manager
                self.__props = props
-               self.__cancelId = None
+               self._delayedCancel = gobject_utils.Async(self._on_cancel)
 
                if telepathy.interfaces.CHANNEL_INTERFACE + '.InitiatorHandle' in props:
                        self._initiator = connection.get_handle_by_id(
@@ -87,7 +88,7 @@ class CallChannel(
        def initial_video(self):
                return False
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def Close(self):
                self.close()
 
@@ -95,47 +96,45 @@ class CallChannel(
                _moduleLogger.debug("Closing call")
                tp.ChannelTypeStreamedMedia.Close(self)
                self.remove_from_connection()
-               if self.__cancelId is not None:
-                       gobject.source_remove(self.__cancelId)
-                       self.__cancelId = None
+               self._delayedCancel.cancel()
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def GetLocalPendingMembersWithInfo(self):
                info = dbus.Array([], signature="(uuus)")
                for member in self._local_pending:
                        info.append((member, self._handle, 0, ''))
                return info
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def AddMembers(self, handles, message):
                _moduleLogger.info("Add members %r: %s" % (handles, message))
                for handle in handles:
                        if handle == int(self.GetSelfHandle()) and self.GetSelfHandle() in self._local_pending:
                                _moduleLogger.info("Technically the user just accepted the call")
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def RemoveMembers(self, handles, message):
                _moduleLogger.info("Remove members (no-op) %r: %s" % (handles, message))
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def RemoveMembersWithReason(self, handles, message, reason):
                _moduleLogger.info("Remove members (no-op) %r: %s (%i)" % (handles, message, reason))
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def ListStreams(self):
                """
                For org.freedesktop.Telepathy.Channel.Type.StreamedMedia
                """
                return ()
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def RemoveStreams(self, streams):
                """
                For org.freedesktop.Telepathy.Channel.Type.StreamedMedia
                """
                raise telepathy.errors.NotImplemented("Cannot remove a stream")
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def RequestStreamDirection(self, stream, streamDirection):
                """
                For org.freedesktop.Telepathy.Channel.Type.StreamedMedia
@@ -145,7 +144,7 @@ class CallChannel(
                _moduleLogger.info("A request was made to change the stream direction")
                raise telepathy.errors.NotImplemented("Cannot change directions")
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def RequestStreams(self, contactId, streamTypes):
                """
                For org.freedesktop.Telepathy.Channel.Type.StreamedMedia
@@ -157,7 +156,7 @@ class CallChannel(
                contactNumber = contact.phoneNumber
 
                self.CallStateChanged(self.__contactHandle, telepathy.constants.CHANNEL_CALL_STATE_RINGING)
-               self.__cancelId = gobject.idle_add(self._on_cancel)
+               self._delayedCancel.start()
                self._conn.session.backend.call(contactNumber)
 
                streamId = 0
@@ -166,7 +165,7 @@ class CallChannel(
                pendingSendFlags = telepathy.constants.MEDIA_STREAM_PENDING_REMOTE_SEND
                return [(streamId, contact, streamTypes[0], streamState, streamDirection, pendingSendFlags)]
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def GetCallStates(self):
                """
                For org.freedesktop.Telepathy.Channel.Interface.CallState
@@ -176,9 +175,7 @@ class CallChannel(
                """
                return {self.__contactHandle: telepathy.constants.CHANNEL_CALL_STATE_FORWARDED}
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def _on_cancel(self, *args):
                self.CallStateChanged(self.__contactHandle, telepathy.constants.CHANNEL_CALL_STATE_FORWARDED)
                self.close()
-               self.__cancelId = None
-               return False
index 8409991..e184d2d 100644 (file)
@@ -4,7 +4,7 @@ import telepathy
 
 import tp
 import util.coroutines as coroutines
-import gtk_toolbox
+import util.misc as misc_utils
 import handle
 
 
@@ -48,7 +48,7 @@ class AllContactsListChannel(
                self.GroupFlagsChanged(0, 0)
 
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def Close(self):
                self.close()
 
@@ -63,11 +63,11 @@ class AllContactsListChannel(
                tp.ChannelTypeContactList.Close(self)
                self.remove_from_connection()
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def GetLocalPendingMembersWithInfo(self):
                return []
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def _on_contacts_refreshed(self, addressbook, added, removed, changed):
                self._process_refresh(addressbook, added, removed, changed)
 
index 2a1c188..049754a 100644 (file)
@@ -7,7 +7,7 @@ import telepathy
 
 import constants
 import tp
-import gtk_toolbox
+import util.misc as misc_utils
 
 
 _moduleLogger = logging.getLogger("channel.debug_log")
@@ -79,7 +79,7 @@ class DebugLogChannel(tp.ChannelTypeFileTransfer):
        def get_initial_offset(self):
                return 0
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def AcceptFile(self, addressType, accessControl, accessControlParam, offset):
                _moduleLogger.info("%r %r %r %r" % (addressType, accessControl, accessControlParam, offset))
                self.InitialOffsetDefined(0)
@@ -111,11 +111,11 @@ class DebugLogChannel(tp.ChannelTypeFileTransfer):
                        telepathy.constants.FILE_TRANSFER_STATE_CHANGE_REASON_NONE,
                )
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def ProvideFile(self, addressType, accessControl, accessControlParam):
                raise telepathy.errors.NotImplemented("Cannot send outbound files")
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def Close(self):
                self.close()
 
index 6b7cebc..9db5554 100644 (file)
@@ -11,7 +11,7 @@ import telepathy
 
 import constants
 import tp
-import gtk_toolbox
+import util.misc as misc_utils
 import gvoice
 
 
@@ -32,7 +32,7 @@ class DebugPromptChannel(tp.ChannelTypeText, cmd.Cmd):
 
                self.__otherHandle = contactHandle
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def Send(self, messageType, text):
                if messageType != telepathy.CHANNEL_TEXT_MESSAGE_TYPE_NORMAL:
                        raise telepathy.errors.NotImplemented("Unhandled message type: %r" % messageType)
@@ -51,7 +51,7 @@ class DebugPromptChannel(tp.ChannelTypeText, cmd.Cmd):
                if stdoutData:
                        self._report_new_message(stdoutData)
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def Close(self):
                self.close()
 
index c7a7da5..d4cb5c0 100644 (file)
@@ -6,7 +6,7 @@ import telepathy
 
 import tp
 import util.coroutines as coroutines
-import gtk_toolbox
+import util.misc as misc_utils
 
 
 _moduleLogger = logging.getLogger("channel.text")
@@ -53,7 +53,7 @@ class TextChannel(tp.ChannelTypeText):
                else:
                        self._report_conversation(mergedConversations)
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def Send(self, messageType, text):
                if messageType != telepathy.CHANNEL_TEXT_MESSAGE_TYPE_NORMAL:
                        raise telepathy.errors.NotImplemented("Unhandled message type: %r" % messageType)
@@ -79,7 +79,7 @@ class TextChannel(tp.ChannelTypeText):
 
                self.Sent(int(time.time()), messageType, text)
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def Close(self):
                self.close()
 
@@ -101,7 +101,7 @@ class TextChannel(tp.ChannelTypeText):
                contactKey = self.__otherHandle.phoneNumber
                return contactKey
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def _on_conversations_updated(self, conv, conversationIds):
                if self._contactKey not in conversationIds:
                        return
index 04faca1..ee844c0 100644 (file)
@@ -5,7 +5,7 @@ import telepathy
 
 import tp
 import channel
-import util.misc as util_misc
+import util.misc as misc_utils
 
 
 _moduleLogger = logging.getLogger("channel_manager")
@@ -69,7 +69,7 @@ class ChannelManager(tp.ChannelManager):
        def _get_text_channel(self, props):
                _, surpress_handler, h = self._get_type_requested_handle(props)
 
-               accountNumber = util_misc.normalize_number(self._conn.session.backend.get_account_number())
+               accountNumber = misc_utils.normalize_number(self._conn.session.backend.get_account_number())
                if h.phoneNumber == accountNumber:
                        _moduleLogger.debug('New Debug channel')
                        chan = channel.debug_prompt.DebugPromptChannel(self._conn, self, props, h)
index 73ec4a4..88a02e6 100644 (file)
@@ -6,8 +6,8 @@ import telepathy
 
 import constants
 import tp
-import util.misc as util_misc
-import gtk_toolbox
+import util.go_utils as gobject_utils
+import util.misc as misc_utils
 
 import gvoice
 import handle
@@ -82,14 +82,14 @@ class TheOneRingConnection(
                "password",
        ))
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def __init__(self, manager, parameters):
                self.check_parameters(parameters)
                account = unicode(parameters['account'])
                encodedAccount = parameters['account'].encode('utf-8')
                encodedPassword = parameters['password'].encode('utf-8')
-               encodedCallback = util_misc.normalize_number(parameters['forward'].encode('utf-8'))
-               if encodedCallback and not util_misc.is_valid_number(encodedCallback):
+               encodedCallback = misc_utils.normalize_number(parameters['forward'].encode('utf-8'))
+               if encodedCallback and not misc_utils.is_valid_number(encodedCallback):
                        raise telepathy.errors.InvalidArgument("Invalid forwarding number")
 
                # Connection init must come first
@@ -136,6 +136,7 @@ class TheOneRingConnection(
                        autogv.RefreshVoicemail(weakref.ref(self)),
                        autogv.AutoDisconnect(weakref.ref(self)),
                ]
+               self._delayedConnect = gobject_utils.Async(self._delayed_connect)
 
                _moduleLogger.info("Connection to the account %s created" % account)
 
@@ -176,11 +177,19 @@ class TheOneRingConnection(
        def _channel_manager(self):
                return self.__channelManager
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def Connect(self):
                """
                For org.freedesktop.telepathy.Connection
                """
+               if self._status != telepathy.CONNECTION_STATUS_DISCONNECTED:
+                       _moduleLogger.info("Attempting connect when not disconnected")
+                       return
+               _moduleLogger.info("Kicking off connect")
+               self._delayedConnect.start()
+
+       @misc_utils.log_exception(_moduleLogger)
+       def _delayed_connect(self):
                _moduleLogger.info("Connecting...")
                self.StatusChanged(
                        telepathy.CONNECTION_STATUS_CONNECTING,
@@ -196,7 +205,7 @@ class TheOneRingConnection(
                                callback = gvoice.backend.get_sane_callback(
                                        self.session.backend
                                )
-                               self.__callbackNumberParameter = util_misc.normalize_number(callback)
+                               self.__callbackNumberParameter = misc_utils.normalize_number(callback)
                        self.session.backend.set_callback_number(self.__callbackNumberParameter)
 
                        subscribeHandle = self.get_handle_by_name(telepathy.HANDLE_TYPE_LIST, "subscribe")
@@ -220,17 +229,15 @@ class TheOneRingConnection(
                        telepathy.CONNECTION_STATUS_REASON_REQUESTED
                )
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def Disconnect(self):
                """
                For org.freedesktop.telepathy.Connection
                """
-               try:
-                       self.disconnect(telepathy.CONNECTION_STATUS_REASON_REQUESTED)
-               except Exception:
-                       _moduleLogger.exception("Error durring disconnect")
+               _moduleLogger.info("Kicking off disconnect")
+               self._delayed_disconnect()
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def RequestChannel(self, type, handleType, handleId, suppressHandler):
                """
                For org.freedesktop.telepathy.Connection
@@ -267,8 +274,16 @@ class TheOneRingConnection(
 
                return props
 
+       @gobject_utils.async
+       def _delayed_disconnect(self):
+               self.disconnect(telepathy.CONNECTION_STATUS_REASON_REQUESTED)
+               return False
+
        def disconnect(self, reason):
                _moduleLogger.info("Disconnecting")
+
+               self._delayedConnect.cancel()
+
                # Not having the disconnect first can cause weird behavior with clients
                # including not being able to reconnect or even crashing
                self.StatusChanged(
index 92a12ae..64b6bf8 100644 (file)
@@ -1,12 +1,11 @@
 import logging
 
-import gobject
 import telepathy
 
 import constants
 import tp
-import gtk_toolbox
 import util.go_utils as gobject_utils
+import util.misc as misc_utils
 import connection
 
 
@@ -23,7 +22,7 @@ class TheOneRingConnectionManager(tp.ConnectionManager):
                self._on_shutdown = shutdown_func
                _moduleLogger.info("Connection manager created")
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def GetParameters(self, proto):
                """
                For org.freedesktop.telepathy.ConnectionManager
@@ -75,7 +74,7 @@ class TheOneRingConnectionManager(tp.ConnectionManager):
                        connection.Disconnect()
                _moduleLogger.info("Connection manager quitting")
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def _shutdown(self):
                if (
                        self._on_shutdown is not None and
index 8a7d16b..fd41265 100644 (file)
@@ -3,6 +3,8 @@ import logging
 import dbus
 import telepathy
 
+import util.misc as misc_utils
+
 
 _moduleLogger = logging.getLogger('contacts')
 
@@ -32,6 +34,7 @@ class ContactsMixin(telepathy.server.ConnectionInterfaceContacts):
                raise NotImplementedError("Abstract function called")
 
        # Overwrite the dbus attribute to get the sender argument
+       @misc_utils.log_exception(_moduleLogger)
        @dbus.service.method(telepathy.CONNECTION_INTERFACE_CONTACTS, in_signature='auasb',
                                                        out_signature='a{ua{sv}}', sender_keyword='sender')
        def GetContactAttributes(self, handles, interfaces, hold, sender):
diff --git a/src/gtk_toolbox.py b/src/gtk_toolbox.py
deleted file mode 100644 (file)
index 09ce9fe..0000000
+++ /dev/null
@@ -1,280 +0,0 @@
-#!/usr/bin/python
-
-from __future__ import with_statement
-
-import os
-import errno
-import time
-import functools
-import contextlib
-import logging
-import threading
-import Queue
-
-
-_moduleLogger = logging.getLogger("gtk_toolbox")
-
-
-@contextlib.contextmanager
-def flock(path, timeout=-1):
-       WAIT_FOREVER = -1
-       DELAY = 0.1
-       timeSpent = 0
-
-       acquired = False
-
-       while timeSpent <= timeout or timeout == WAIT_FOREVER:
-               try:
-                       fd = os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDWR)
-                       acquired = True
-                       break
-               except OSError, e:
-                       if e.errno != errno.EEXIST:
-                               raise
-               time.sleep(DELAY)
-               timeSpent += DELAY
-
-       assert acquired, "Failed to grab file-lock %s within timeout %d" % (path, timeout)
-
-       try:
-               yield fd
-       finally:
-               os.unlink(path)
-
-
-def make_idler(func):
-       """
-       Decorator that makes a generator-function into a function that will continue execution on next call
-       """
-       a = []
-
-       @functools.wraps(func)
-       def decorated_func(*args, **kwds):
-               if not a:
-                       a.append(func(*args, **kwds))
-               try:
-                       a[0].next()
-                       return True
-               except StopIteration:
-                       del a[:]
-                       return False
-
-       return decorated_func
-
-
-def autostart(func):
-       """
-       >>> @autostart
-       ... def grep_sink(pattern):
-       ...     print "Looking for %s" % pattern
-       ...     while True:
-       ...             line = yield
-       ...             if pattern in line:
-       ...                     print line,
-       >>> g = grep_sink("python")
-       Looking for python
-       >>> g.send("Yeah but no but yeah but no")
-       >>> g.send("A series of tubes")
-       >>> g.send("python generators rock!")
-       python generators rock!
-       >>> g.close()
-       """
-
-       @functools.wraps(func)
-       def start(*args, **kwargs):
-               cr = func(*args, **kwargs)
-               cr.next()
-               return cr
-
-       return start
-
-
-@autostart
-def printer_sink(format = "%s"):
-       """
-       >>> pr = printer_sink("%r")
-       >>> pr.send("Hello")
-       'Hello'
-       >>> pr.send("5")
-       '5'
-       >>> pr.send(5)
-       5
-       >>> p = printer_sink()
-       >>> p.send("Hello")
-       Hello
-       >>> p.send("World")
-       World
-       >>> # p.throw(RuntimeError, "Goodbye")
-       >>> # p.send("Meh")
-       >>> # p.close()
-       """
-       while True:
-               item = yield
-               print format % (item, )
-
-
-@autostart
-def null_sink():
-       """
-       Good for uses like with cochain to pick up any slack
-       """
-       while True:
-               item = yield
-
-
-@autostart
-def comap(function, target):
-       """
-       >>> p = printer_sink()
-       >>> cm = comap(lambda x: x+1, p)
-       >>> cm.send((0, ))
-       1
-       >>> cm.send((1.0, ))
-       2.0
-       >>> cm.send((-2, ))
-       -1
-       """
-       while True:
-               try:
-                       item = yield
-                       mappedItem = function(*item)
-                       target.send(mappedItem)
-               except Exception, e:
-                       _moduleLogger.exception("Forwarding exception!")
-                       target.throw(e.__class__, str(e))
-
-
-def _flush_queue(queue):
-       while not queue.empty():
-               yield queue.get()
-
-
-@autostart
-def queue_sink(queue):
-       """
-       >>> q = Queue.Queue()
-       >>> qs = queue_sink(q)
-       >>> qs.send("Hello")
-       >>> qs.send("World")
-       >>> qs.throw(RuntimeError, "Goodbye")
-       >>> qs.send("Meh")
-       >>> qs.close()
-       >>> print [i for i in _flush_queue(q)]
-       [(None, 'Hello'), (None, 'World'), (<type 'exceptions.RuntimeError'>, 'Goodbye'), (None, 'Meh'), (<type 'exceptions.GeneratorExit'>, None)]
-       """
-       while True:
-               try:
-                       item = yield
-                       queue.put((None, item))
-               except Exception, e:
-                       queue.put((e.__class__, str(e)))
-               except GeneratorExit:
-                       queue.put((GeneratorExit, None))
-                       raise
-
-
-def decode_item(item, target):
-       if item[0] is None:
-               target.send(item[1])
-               return False
-       elif item[0] is GeneratorExit:
-               target.close()
-               return True
-       else:
-               target.throw(item[0], item[1])
-               return False
-
-
-def nonqueue_source(queue, target):
-       isDone = False
-       while not isDone:
-               item = queue.get()
-               isDone = decode_item(item, target)
-               while not queue.empty():
-                       queue.get_nowait()
-
-
-def threaded_stage(target, thread_factory = threading.Thread):
-       messages = Queue.Queue()
-
-       run_source = functools.partial(nonqueue_source, messages, target)
-       thread = thread_factory(target=run_source)
-       thread.setDaemon(True)
-       thread.start()
-
-       # Sink running in current thread
-       return queue_sink(messages)
-
-
-def safecall(f, errorDisplay=None, default=None, exception=Exception):
-       '''
-       Returns modified f. When the modified f is called and throws an
-       exception, the default value is returned
-       '''
-       def _safecall(*args, **argv):
-               try:
-                       return f(*args, **argv)
-               except exception, e:
-                       if errorDisplay is not None:
-                               errorDisplay.push_exception(e)
-                       return default
-       return _safecall
-
-
-def log_call(logger):
-
-       def log_call_decorator(func):
-
-               @functools.wraps(func)
-               def wrapper(*args, **kwds):
-                       _moduleLogger.info("-> %s" % (func.__name__, ))
-                       try:
-                               return func(*args, **kwds)
-                       finally:
-                               _moduleLogger.info("<- %s" % (func.__name__, ))
-
-               return wrapper
-
-       return log_call_decorator
-
-
-def log_exception(logger):
-
-       def log_exception_decorator(func):
-
-               @functools.wraps(func)
-               def wrapper(*args, **kwds):
-                       try:
-                               return func(*args, **kwds)
-                       except Exception:
-                               logger.exception(func.__name__)
-                               raise
-
-               return wrapper
-
-       return log_exception_decorator
-
-
-_indentationLevel = [0]
-
-
-def trace(logger):
-
-       def trace_decorator(func):
-
-               @functools.wraps(func)
-               def wrapper(*args, **kwds):
-                       try:
-                               logger.debug("%s> %s" % (" " * _indentationLevel[0], func.__name__, ))
-                               _indentationLevel[0] += 1
-                               return func(*args, **kwds)
-                       except Exception:
-                               logger.exception(func.__name__)
-                               raise
-                       finally:
-                               _indentationLevel[0] -= 1
-                               logger.debug("%s< %s" % (" " * _indentationLevel[0], func.__name__, ))
-
-               return wrapper
-
-       return trace_decorator
index 9071b19..f5fa02e 100644 (file)
@@ -4,7 +4,7 @@
 import logging
 
 import util.coroutines as coroutines
-import util.misc as util_misc
+import util.misc as misc_utils
 
 
 _moduleLogger = logging.getLogger("gvoice.addressbook")
@@ -72,7 +72,7 @@ class Addressbook(object):
                        contactName = contactDetails["name"]
                        contactNumbers = (
                                (
-                                       util_misc.normalize_number(numberDetails["phoneNumber"]),
+                                       misc_utils.normalize_number(numberDetails["phoneNumber"]),
                                        numberDetails.get("phoneType", "Mobile"),
                                )
                                for numberDetails in contactDetails["numbers"]
index 7fbe1ca..4ccce3a 100644 (file)
@@ -12,7 +12,7 @@ except ImportError:
 
 import constants
 import util.coroutines as coroutines
-import util.misc as util_misc
+import util.misc as misc_utils
 
 
 _moduleLogger = logging.getLogger("gvoice.conversations")
@@ -64,7 +64,7 @@ class Conversations(object):
                conversations = list(self._get_raw_conversations())
                conversations.sort()
                for conversation in conversations:
-                       key = util_misc.normalize_number(conversation.number)
+                       key = misc_utils.normalize_number(conversation.number)
                        try:
                                mergedConversations = self._conversations[key]
                        except KeyError:
index bb58c7e..4dcd809 100644 (file)
@@ -6,7 +6,7 @@ import gobject
 
 import util.go_utils as gobject_utils
 import util.coroutines as coroutines
-import gtk_toolbox
+import util.misc as misc_utils
 
 
 _moduleLogger = logging.getLogger("gvoice.state_machine")
@@ -228,7 +228,7 @@ class UpdateStateMachine(StateMachine):
                self._maxTime = maxTime
 
                self._state = self.STATE_ACTIVE
-               self._timeoutId = None
+               self._onTimeout = gobject_utils.Timeout(self._on_timeout)
 
                self._strategies = {}
                self._callback = coroutines.func_sink(
@@ -247,19 +247,18 @@ class UpdateStateMachine(StateMachine):
                self._strategies[state] = strategy
 
        def start(self):
-               assert self._timeoutId is None
                for strategy in self._strategies.itervalues():
                        strategy.initialize_state()
                if self._strategy.timeout != self.INFINITE_PERIOD:
-                       self._timeoutId = gobject.idle_add(self._on_timeout)
+                       self._onTimeout.start(seconds=0)
                _moduleLogger.info("%s Starting State Machine" % (self._name, ))
 
        def stop(self):
                _moduleLogger.info("%s Stopping State Machine" % (self._name, ))
-               self._stop_update()
+               self._onTimeout.cancel()
 
        def close(self):
-               assert self._timeoutId is None
+               self._onTimeout.cancel()
                self._callback = None
 
        def set_state(self, newState):
@@ -290,7 +289,7 @@ class UpdateStateMachine(StateMachine):
        def maxTime(self):
                return self._maxTime
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def _request_reset_timers(self, *args):
                self._reset_timers()
 
@@ -298,37 +297,28 @@ class UpdateStateMachine(StateMachine):
                if self._timeoutId is None:
                        return # not started yet
                _moduleLogger.info("%s Resetting State Machine" % (self._name, ))
-               self._stop_update()
+               self._onTimeout.cancel()
                if initialize:
                        self._strategy.initialize_state()
                else:
                        self._strategy.reinitialize_state()
                self._schedule_update()
 
-       def _stop_update(self):
-               if self._timeoutId is None:
-                       return
-               gobject.source_remove(self._timeoutId)
-               self._timeoutId = None
-
        def _schedule_update(self):
-               assert self._timeoutId is None
                self._strategy.increment_state()
                nextTimeout = self._strategy.timeout
                if nextTimeout != self.INFINITE_PERIOD and nextTimeout < self._maxTime:
                        assert 0 < nextTimeout
-                       self._timeoutId = gobject_utils.timeout_add_seconds(nextTimeout, self._on_timeout)
+                       self._onTimeout.start(seconds=nextTimeout)
                        _moduleLogger.info("%s Next update in %s seconds" % (self._name, nextTimeout, ))
                else:
                        _moduleLogger.info("%s No further updates (timeout is %s seconds)" % (self._name, nextTimeout, ))
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def _on_timeout(self):
-               self._timeoutId = None
                self._schedule_update()
                for item in self._updateItems:
                        try:
                                item.update(force=True)
                        except Exception:
                                _moduleLogger.exception("Update failed for %r" % item)
-               return False # do not continue
index 5fc4e98..9baf35b 100644 (file)
@@ -4,7 +4,7 @@ import weakref
 import telepathy
 
 import tp
-import util.misc as util_misc
+import util.misc as misc_utils
 
 
 _moduleLogger = logging.getLogger("handle")
@@ -42,7 +42,7 @@ class ConnectionHandle(TheOneRingHandle):
 class ContactHandle(TheOneRingHandle):
 
        def __init__(self, connection, id, phoneNumber):
-               self._phoneNumber = util_misc.normalize_number(phoneNumber)
+               self._phoneNumber = misc_utils.normalize_number(phoneNumber)
 
                handleType = telepathy.HANDLE_TYPE_CONTACT
                handleName = self._phoneNumber
index 59195fd..a77d0c7 100644 (file)
@@ -2,7 +2,7 @@ import logging
 
 import telepathy
 
-import gtk_toolbox
+import util.misc as misc_utils
 
 
 _moduleLogger = logging.getLogger('location')
@@ -22,21 +22,21 @@ class LocationMixin(object):
                """
                raise NotImplementedError("Abstract property called")
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def GetLocations(self, contacts):
                """
                @returns {Contact: {Location Type: Location}}
                """
                raise telepathy.errors.NotImplemented("Yet")
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def RequestLocation(self, contact):
                """
                @returns {Location Type: Location}
                """
                raise telepathy.errors.NotImplemented("Yet")
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def SetLocation(self, location):
                """
                Since presence is based off of phone numbers, not allowing the client to change it
index ab6fc66..c73a061 100644 (file)
@@ -1,7 +1,7 @@
 import logging
 
 import tp
-import gtk_toolbox
+import util.misc as misc_utils
 import simple_presence
 
 
@@ -14,7 +14,7 @@ class PresenceMixin(tp.ConnectionInterfacePresence, simple_presence.TheOneRingPr
                tp.ConnectionInterfacePresence.__init__(self)
                simple_presence.TheOneRingPresence.__init__(self)
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def GetStatuses(self):
                # the arguments are in common to all on-line presences
                arguments = {}
@@ -24,16 +24,16 @@ class PresenceMixin(tp.ConnectionInterfacePresence, simple_presence.TheOneRingPr
                        for (localType, telepathyType) in self.TO_PRESENCE_TYPE.iteritems()
                )
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def RequestPresence(self, contactIds):
                presences = self.__get_presences(contactIds)
                self.PresenceUpdate(presences)
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def GetPresence(self, contactIds):
                return self.__get_presences(contactIds)
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def SetStatus(self, statuses):
                assert len(statuses) == 1
                status, arguments = statuses.items()[0]
index 5449344..ac8b875 100644 (file)
@@ -2,7 +2,7 @@ import logging
 
 import telepathy
 
-import gtk_toolbox
+import util.misc as misc_utils
 import tp
 import handle
 import gvoice.state_machine as state_machine
@@ -98,7 +98,7 @@ class SimplePresenceMixin(tp.ConnectionInterfaceSimplePresence, TheOneRingPresen
                        {'Statuses' : self._get_statuses}
                )
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def GetPresences(self, contacts):
                """
                @return {ContactHandle: (Status, Presence Type, Message)}
@@ -109,7 +109,7 @@ class SimplePresenceMixin(tp.ConnectionInterfaceSimplePresence, TheOneRingPresen
                        for (h, (presenceType, presence)) in self.get_presences(contacts).iteritems()
                )
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def SetPresence(self, status, message):
                if message:
                        raise telepathy.errors.InvalidArgument("Messages aren't supported")
index 2753ec8..8b72dff 100644 (file)
@@ -4,9 +4,35 @@ from __future__ import with_statement
 
 import time
 import functools
+import logging
 
 import gobject
 
+import misc
+
+
+_moduleLogger = logging.getLogger("go_utils")
+
+
+def make_idler(func):
+       """
+       Decorator that makes a generator-function into a function that will continue execution on next call
+       """
+       a = []
+
+       @functools.wraps(func)
+       def decorated_func(*args, **kwds):
+               if not a:
+                       a.append(func(*args, **kwds))
+               try:
+                       a[0].next()
+                       return True
+               except StopIteration:
+                       del a[:]
+                       return False
+
+       return decorated_func
+
 
 def async(func):
        """
@@ -29,6 +55,65 @@ def async(func):
        return new_function
 
 
+class Async(object):
+
+       def __init__(self, func, once = True):
+               self.__func = func
+               self.__idleId = None
+               self.__once = once
+
+       def start(self):
+               assert self.__idleId is None
+               if self.__once:
+                       self.__idleId = gobject.idle_add(self._on_once)
+               else:
+                       self.__idleId = gobject.idle_add(self.__func)
+
+       def cancel(self):
+               if self.__idleId is not None:
+                       gobject.source_remove(self.__idleId)
+                       self.__idleId = None
+
+       @misc.log_exception(_moduleLogger)
+       def _on_once(self):
+               self.cancel()
+               try:
+                       self.__func()
+               finally:
+                       return False
+
+
+class Timeout(object):
+
+       def __init__(self, func):
+               self.__func = func
+               self.__timeoutId = None
+
+       def start(self, **kwds):
+               assert self.__timeoutId is None
+
+               assert len(kwds) == 1
+               timeoutInSeconds = kwds["seconds"]
+               assert 0 <= timeoutInSeconds
+               if timeoutInSeconds == 0:
+                       self.__timeoutId = gobject.idle_add(self._on_once)
+               else:
+                       timeout_add_seconds(timeoutInSeconds, self._on_once)
+
+       def cancel(self):
+               if self.__timeoutId is not None:
+                       gobject.source_remove(self.__timeoutId)
+                       self.__timeoutId = None
+
+       @misc.log_exception(_moduleLogger)
+       def _on_once(self):
+               self.cancel()
+               try:
+                       self.__func()
+               finally:
+                       return False
+
+
 def throttled(minDelay, queue):
        """
        Throttle the calls to a function by queueing all the calls that happen
index ba5f506..69a5b09 100644 (file)
@@ -16,6 +16,45 @@ import warnings
 import string
 
 
+_indentationLevel = [0]
+
+
+def log_call(logger):
+
+       def log_call_decorator(func):
+
+               @functools.wraps(func)
+               def wrapper(*args, **kwds):
+                       logger.debug("%s> %s" % (" " * _indentationLevel[0], func.__name__, ))
+                       _indentationLevel[0] += 1
+                       try:
+                               return func(*args, **kwds)
+                       finally:
+                               _indentationLevel[0] -= 1
+                               logger.debug("%s< %s" % (" " * _indentationLevel[0], func.__name__, ))
+
+               return wrapper
+
+       return log_call_decorator
+
+
+def log_exception(logger):
+
+       def log_exception_decorator(func):
+
+               @functools.wraps(func)
+               def wrapper(*args, **kwds):
+                       try:
+                               return func(*args, **kwds)
+                       except Exception:
+                               logger.exception(func.__name__)
+                               raise
+
+               return wrapper
+
+       return log_exception_decorator
+
+
 def printfmt(template):
        """
        This hides having to create the Template object and call substitute/safe_substitute on it. For example:
index dbf06ec..9ae525b 100644 (file)
@@ -7,7 +7,7 @@ import dbus
 import telepathy
 
 import util.go_utils as gobject_utils
-import gtk_toolbox
+import misc
 
 
 _moduleLogger = logging.getLogger("tp_utils")
@@ -25,7 +25,8 @@ class WasMissedCall(object):
                self._didClose = False
                self._didReport = False
 
-               self._timeoutId = gobject_utils.timeout_add_seconds(10, self._on_timeout)
+               self._onTimeout = misc.Timeout(self._on_timeout)
+               self._onTimeout.start(seconds=10)
 
                chan[telepathy.interfaces.CHANNEL_INTERFACE_GROUP].connect_to_signal(
                        "MembersChanged",
@@ -63,40 +64,36 @@ class WasMissedCall(object):
        def _report_success(self):
                assert not self._didReport
                self._didReport = True
-               if self._timeoutId:
-                       gobject.source_remove(self._timeoutId)
-                       self._timeoutId = None
+               self._onTimeout.cancel()
                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._onTimeout.cancel()
                self._on_error(self, reason)
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc.log_exception(_moduleLogger)
        def _on_got_all(self, properties):
                self._requested = properties["Requested"]
                self._report_missed_if_ready()
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc.log_exception(_moduleLogger)
        def _on_members_changed(self, message, added, removed, lp, rp, actor, reason):
                if added:
                        self._didMembersChange = True
                        self._report_missed_if_ready()
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc.log_exception(_moduleLogger)
        def _on_closed(self):
                self._didClose = True
                self._report_missed_if_ready()
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc.log_exception(_moduleLogger)
        def _on_error(self, *args):
                self._report_error(args)
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc.log_exception(_moduleLogger)
        def _on_timeout(self):
                self._report_error("timeout")
                return False
@@ -126,7 +123,7 @@ class NewChannelSignaller(object):
                        None
                )
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc.log_exception(_moduleLogger)
        def _on_new_channel(
                self, channelObjectPath, channelType, handleType, handle, supressHandler
        ):