Separating voicemail / texts into their own state machines
authorEd Page <eopage@byu.net>
Fri, 8 Jan 2010 03:27:10 +0000 (21:27 -0600)
committerEd Page <eopage@byu.net>
Fri, 8 Jan 2010 03:27:10 +0000 (21:27 -0600)
src/channel/text.py
src/connection.py
src/gvoice/backend.py
src/gvoice/conversations.py
src/gvoice/session.py
src/gvoice/state_machine.py

index 4eb601d..2b39833 100644 (file)
@@ -37,14 +37,23 @@ class TextChannel(telepathy.server.ChannelTypeText):
                                self._on_conversations_updated
                        )
                )
                                self._on_conversations_updated
                        )
                )
-               self._conn.session.conversations.updateSignalHandler.register_sink(
+               self._conn.session.voicemails.updateSignalHandler.register_sink(
+                       self._callback
+               )
+               self._conn.session.texts.updateSignalHandler.register_sink(
                        self._callback
                )
 
                # The only reason there should be anything in the conversation is if
                # its new, so report it all
                try:
                        self._callback
                )
 
                # The only reason there should be anything in the conversation is if
                # its new, so report it all
                try:
-                       mergedConversations = self._conn.session.conversations.get_conversation(self._contactKey)
+                       mergedConversations = self._conn.session.voicemails.get_conversation(self._contactKey)
+               except KeyError:
+                       _moduleLogger.info("Nothing in the conversation yet for %r" % (self._contactKey, ))
+               else:
+                       self._report_conversation(mergedConversations)
+               try:
+                       mergedConversations = self._conn.session.texts.get_conversation(self._contactKey)
                except KeyError:
                        _moduleLogger.info("Nothing in the conversation yet for %r" % (self._contactKey, ))
                else:
                except KeyError:
                        _moduleLogger.info("Nothing in the conversation yet for %r" % (self._contactKey, ))
                else:
@@ -56,7 +65,7 @@ class TextChannel(telepathy.server.ChannelTypeText):
                        raise telepathy.errors.NotImplemented("Unhandled message type: %r" % messageType)
 
                self._conn.session.backend.send_sms(self._otherHandle.phoneNumber, text)
                        raise telepathy.errors.NotImplemented("Unhandled message type: %r" % messageType)
 
                self._conn.session.backend.send_sms(self._otherHandle.phoneNumber, text)
-               self._conn.session.conversationsStateMachine.reset_timers()
+               self._conn.session.textsStateMachine.reset_timers()
 
                self.Sent(int(time.time()), messageType, text)
 
 
                self.Sent(int(time.time()), messageType, text)
 
@@ -65,7 +74,10 @@ class TextChannel(telepathy.server.ChannelTypeText):
                self.close()
 
        def close(self):
                self.close()
 
        def close(self):
-               self._conn.session.conversations.updateSignalHandler.unregister_sink(
+               self._conn.session.voicemails.updateSignalHandler.unregister_sink(
+                       self._callback
+               )
+               self._conn.session.texts.updateSignalHandler.unregister_sink(
                        self._callback
                )
                self._callback = None
                        self._callback
                )
                self._callback = None
@@ -87,7 +99,7 @@ class TextChannel(telepathy.server.ChannelTypeText):
                if self._contactKey not in conversationIds:
                        return
                _moduleLogger.info("Incoming messages from %r for existing conversation" % (self._contactKey, ))
                if self._contactKey not in conversationIds:
                        return
                _moduleLogger.info("Incoming messages from %r for existing conversation" % (self._contactKey, ))
-               mergedConversations = self._conn.session.conversations.get_conversation(self._contactKey)
+               mergedConversations = conv.get_conversation(self._contactKey)
                self._report_conversation(mergedConversations)
 
        def _report_conversation(self, mergedConversations):
                self._report_conversation(mergedConversations)
 
        def _report_conversation(self, mergedConversations):
index 18bdd4e..8885232 100644 (file)
@@ -1,12 +1,9 @@
 
 """
 
 """
-@todo Add params for disable/enable state machines
-@todo Separate voicemail/sms into separate conversation instances
-@todo Setup addressbook, voicemail, sms state machines
+@todo Add params for different state machines update times
 @todo Add option to use screen name as callback
 @todo Get a callback for missed calls to force an update of the voicemail state machine
 @todo Get a callback on an incoming call and if its from GV, auto-pickup
 @todo Add option to use screen name as callback
 @todo Get a callback for missed calls to force an update of the voicemail state machine
 @todo Get a callback on an incoming call and if its from GV, auto-pickup
-@todo Use state-strategies to keep mega-state-machine generic
 @todo Observe when connected/disconnected to disconnect CM
 """
 
 @todo Observe when connected/disconnected to disconnect CM
 """
 
@@ -137,7 +134,10 @@ class TheOneRingConnection(
                                        self._on_conversations_updated
                                )
                        )
                                        self._on_conversations_updated
                                )
                        )
-                       self.session.conversations.updateSignalHandler.register_sink(
+                       self.session.voicemails.updateSignalHandler.register_sink(
+                               self._callback
+                       )
+                       self.session.texts.updateSignalHandler.register_sink(
                                self._callback
                        )
                        self.session.login(*self._credentials)
                                self._callback
                        )
                        self.session.login(*self._credentials)
@@ -169,7 +169,10 @@ class TheOneRingConnection(
                """
                _moduleLogger.info("Disconnecting")
                try:
                """
                _moduleLogger.info("Disconnecting")
                try:
-                       self.session.conversations.updateSignalHandler.unregister_sink(
+                       self.session.voicemails.updateSignalHandler.unregister_sink(
+                               self._callback
+                       )
+                       self.session.texts.updateSignalHandler.unregister_sink(
                                self._callback
                        )
                        self._callback = None
                                self._callback
                        )
                        self._callback = None
@@ -256,8 +259,6 @@ class TheOneRingConnection(
        @gobject_utils.async
        @gtk_toolbox.log_exception(_moduleLogger)
        def _on_conversations_updated(self, conv, conversationIds):
        @gobject_utils.async
        @gtk_toolbox.log_exception(_moduleLogger)
        def _on_conversations_updated(self, conv, conversationIds):
-               # @todo get conversations update running
-               # @todo test conversatiuons
                _moduleLogger.info("Incoming messages from: %r" % (conversationIds, ))
                for contactId, phoneNumber in conversationIds:
                        h = handle.create_handle(self, 'contact', contactId, phoneNumber)
                _moduleLogger.info("Incoming messages from: %r" % (conversationIds, ))
                for contactId, phoneNumber in conversationIds:
                        h = handle.create_handle(self, 'contact', contactId, phoneNumber)
index bf9aed1..3b1d568 100755 (executable)
@@ -477,21 +477,21 @@ class GVoiceBackend(object):
                        if contactId != "0":
                                yield contactId, contactDetails
 
                        if contactId != "0":
                                yield contactId, contactDetails
 
-       def get_conversations(self):
+       def get_voicemails(self):
                voicemailPage = self._get_page(self._XML_VOICEMAIL_URL)
                voicemailHtml = self._grab_html(voicemailPage)
                voicemailJson = self._grab_json(voicemailPage)
                parsedVoicemail = self._parse_voicemail(voicemailHtml)
                voicemails = self._merge_conversation_sources(parsedVoicemail, voicemailJson)
                voicemailPage = self._get_page(self._XML_VOICEMAIL_URL)
                voicemailHtml = self._grab_html(voicemailPage)
                voicemailJson = self._grab_json(voicemailPage)
                parsedVoicemail = self._parse_voicemail(voicemailHtml)
                voicemails = self._merge_conversation_sources(parsedVoicemail, voicemailJson)
+               return voicemails
 
 
+       def get_texts(self):
                smsPage = self._get_page(self._XML_SMS_URL)
                smsHtml = self._grab_html(smsPage)
                smsJson = self._grab_json(smsPage)
                parsedSms = self._parse_sms(smsHtml)
                smss = self._merge_conversation_sources(parsedSms, smsJson)
                smsPage = self._get_page(self._XML_SMS_URL)
                smsHtml = self._grab_html(smsPage)
                smsJson = self._grab_json(smsPage)
                parsedSms = self._parse_sms(smsHtml)
                smss = self._merge_conversation_sources(parsedSms, smsJson)
-
-               allConversations = itertools.chain(voicemails, smss)
-               return allConversations
+               return smss
 
        def mark_message(self, messageId, asRead):
                postData = {
 
        def mark_message(self, messageId, asRead):
                postData = {
index 36aca67..d5e060f 100644 (file)
@@ -12,8 +12,8 @@ _moduleLogger = logging.getLogger("gvoice.conversations")
 
 class Conversations(object):
 
 
 class Conversations(object):
 
-       def __init__(self, backend):
-               self._backend = backend
+       def __init__(self, getter):
+               self._get_raw_conversations = getter
                self._conversations = {}
 
                self.updateSignalHandler = coroutines.CoTee()
                self._conversations = {}
 
                self.updateSignalHandler = coroutines.CoTee()
@@ -25,7 +25,7 @@ class Conversations(object):
                oldConversationIds = set(self._conversations.iterkeys())
 
                updateConversationIds = set()
                oldConversationIds = set(self._conversations.iterkeys())
 
                updateConversationIds = set()
-               conversations = list(self._backend.get_conversations())
+               conversations = list(self._get_raw_conversations())
                conversations.sort()
                for conversation in conversations:
                        key = conversation.contactId, util_misc.strip_number(conversation.number)
                conversations.sort()
                for conversation in conversations:
                        key = conversation.contactId, util_misc.strip_number(conversation.number)
index adb551e..0235daa 100644 (file)
@@ -20,7 +20,7 @@ class Session(object):
                self._backend = backend.GVoiceBackend(cookiePath)
 
                self._addressbook = addressbook.Addressbook(self._backend)
                self._backend = backend.GVoiceBackend(cookiePath)
 
                self._addressbook = addressbook.Addressbook(self._backend)
-               self._addressbookStateMachine = state_machine.UpdateStateMachine([self.addressbook])
+               self._addressbookStateMachine = state_machine.UpdateStateMachine([self.addressbook], "Addressbook")
                self._addressbookStateMachine.set_state_strategy(
                        state_machine.StateMachine.STATE_DND,
                        state_machine.NopStateStrategy()
                self._addressbookStateMachine.set_state_strategy(
                        state_machine.StateMachine.STATE_DND,
                        state_machine.NopStateStrategy()
@@ -34,17 +34,35 @@ class Session(object):
                        state_machine.ConstantStateStrategy(state_machine.to_milliseconds(hours=1))
                )
 
                        state_machine.ConstantStateStrategy(state_machine.to_milliseconds(hours=1))
                )
 
-               self._conversations = conversations.Conversations(self._backend)
-               self._conversationsStateMachine = state_machine.UpdateStateMachine([self.conversations])
-               self._conversationsStateMachine.set_state_strategy(
+               self._voicemails = conversations.Conversations(self._backend.get_voicemails)
+               self._voicemailsStateMachine = state_machine.UpdateStateMachine([self.voicemails], "Voicemail")
+               self._voicemailsStateMachine.set_state_strategy(
                        state_machine.StateMachine.STATE_DND,
                        state_machine.NopStateStrategy()
                )
                        state_machine.StateMachine.STATE_DND,
                        state_machine.NopStateStrategy()
                )
-               self._conversationsStateMachine.set_state_strategy(
+               self._voicemailsStateMachine.set_state_strategy(
                        state_machine.StateMachine.STATE_IDLE,
                        state_machine.ConstantStateStrategy(state_machine.to_milliseconds(minutes=30))
                )
                        state_machine.StateMachine.STATE_IDLE,
                        state_machine.ConstantStateStrategy(state_machine.to_milliseconds(minutes=30))
                )
-               self._conversationsStateMachine.set_state_strategy(
+               self._voicemailsStateMachine.set_state_strategy(
+                       state_machine.StateMachine.STATE_ACTIVE,
+                       state_machine.ConstantStateStrategy(state_machine.to_milliseconds(minutes=5))
+               )
+               self._voicemails.updateSignalHandler.register_sink(
+                       self._voicemailsStateMachine.request_reset_timers
+               )
+
+               self._texts = conversations.Conversations(self._backend.get_texts)
+               self._textsStateMachine = state_machine.UpdateStateMachine([self.texts], "Texting")
+               self._textsStateMachine.set_state_strategy(
+                       state_machine.StateMachine.STATE_DND,
+                       state_machine.NopStateStrategy()
+               )
+               self._textsStateMachine.set_state_strategy(
+                       state_machine.StateMachine.STATE_IDLE,
+                       state_machine.ConstantStateStrategy(state_machine.to_milliseconds(minutes=30))
+               )
+               self._textsStateMachine.set_state_strategy(
                        state_machine.StateMachine.STATE_ACTIVE,
                        state_machine.GeometricStateStrategy(
                                state_machine.to_milliseconds(seconds=10),
                        state_machine.StateMachine.STATE_ACTIVE,
                        state_machine.GeometricStateStrategy(
                                state_machine.to_milliseconds(seconds=10),
@@ -52,18 +70,21 @@ class Session(object):
                                state_machine.to_milliseconds(minutes=10),
                        )
                )
                                state_machine.to_milliseconds(minutes=10),
                        )
                )
+               self._texts.updateSignalHandler.register_sink(
+                       self._textsStateMachine.request_reset_timers
+               )
 
                self._masterStateMachine = state_machine.MasterStateMachine()
                self._masterStateMachine.append_machine(self._addressbookStateMachine)
 
                self._masterStateMachine = state_machine.MasterStateMachine()
                self._masterStateMachine.append_machine(self._addressbookStateMachine)
-               self._masterStateMachine.append_machine(self._conversationsStateMachine)
-
-               self._conversations.updateSignalHandler.register_sink(
-                       self._conversationsStateMachine.request_reset_timers
-               )
+               self._masterStateMachine.append_machine(self._voicemailsStateMachine)
+               self._masterStateMachine.append_machine(self._textsStateMachine)
 
        def close(self):
 
        def close(self):
-               self._conversations.updateSignalHandler.unregister_sink(
-                       self._conversationsStateMachine.request_reset_timers
+               self._voicemails.updateSignalHandler.unregister_sink(
+                       self._voicemailsStateMachine.request_reset_timers
+               )
+               self._texts.updateSignalHandler.unregister_sink(
+                       self._textsStateMachine.request_reset_timers
                )
                self._masterStateMachine.close()
 
                )
                self._masterStateMachine.close()
 
@@ -111,17 +132,15 @@ class Session(object):
 
        @property
        def addressbook(self):
 
        @property
        def addressbook(self):
-               """
-               Delay initialized addressbook
-               """
                return self._addressbook
 
        @property
                return self._addressbook
 
        @property
-       def conversations(self):
-               """
-               Delay initialized addressbook
-               """
-               return self._conversations
+       def texts(self):
+               return self._texts
+
+       @property
+       def voicemails(self):
+               return self._voicemails
 
        @property
        def stateMachine(self):
 
        @property
        def stateMachine(self):
@@ -132,5 +151,9 @@ class Session(object):
                return self._addressbookStateMachine
 
        @property
                return self._addressbookStateMachine
 
        @property
-       def conversationsStateMachine(self):
-               return self._conversationsStateMachine
+       def voicemailsStateMachine(self):
+               return self._voicemailsStateMachine
+
+       @property
+       def textsStateMachine(self):
+               return self._textsStateMachine
index d26a57c..3f9fcc2 100644 (file)
@@ -151,7 +151,8 @@ class UpdateStateMachine(StateMachine):
 
        _IS_DAEMON = True
 
 
        _IS_DAEMON = True
 
-       def __init__(self, updateItems):
+       def __init__(self, updateItems, name=""):
+               self._name = name
                self._updateItems = updateItems
 
                self._state = self.STATE_ACTIVE
                self._updateItems = updateItems
 
                self._state = self.STATE_ACTIVE
@@ -204,10 +205,6 @@ class UpdateStateMachine(StateMachine):
        def _strategy(self):
                return self._strategies[self._state]
 
        def _strategy(self):
                return self._strategies[self._state]
 
-       @property
-       def _name(self):
-               return "/".join(type(s).__name__ for s in self._updateItems)
-
        @gobject_utils.async
        @gtk_toolbox.log_exception(_moduleLogger)
        def _request_reset_timers(self, *args):
        @gobject_utils.async
        @gtk_toolbox.log_exception(_moduleLogger)
        def _request_reset_timers(self, *args):