Lots of work to try and get duplex conversations going plus disabled cookies
[theonering] / src / gvoice / conversations.py
1 #!/usr/bin/python
2
3
4 import logging
5
6 import util.coroutines as coroutines
7
8 import backend
9
10
11 _moduleLogger = logging.getLogger("gvoice.conversations")
12
13
14 class Conversations(object):
15
16         def __init__(self, backend):
17                 self._backend = backend
18                 self._conversations = {}
19
20                 self.updateSignalHandler = coroutines.CoTee()
21
22         def update(self, force=False):
23                 if not force and self._conversations:
24                         return
25
26                 oldConversationIds = set(self._conversations.iterkeys())
27
28                 updateConversationIds = set()
29                 messages = self._backend.get_messages()
30                 sortedMessages = backend.sort_messages(messages)
31                 for messageData in sortedMessages:
32                         key = messageData["contactId"], messageData["number"]
33                         try:
34                                 conversation = self._conversations[key]
35                                 isNewConversation = False
36                         except KeyError:
37                                 conversation = Conversation(self._backend, messageData)
38                                 self._conversations[key] = conversation
39                                 isNewConversation = True
40
41                         if isNewConversation:
42                                 # @todo see if this has issues with a user marking a item as unread/unarchive?
43                                 isConversationUpdated = True
44                         else:
45                                 isConversationUpdated = conversation.merge_conversation(messageData)
46
47                         if isConversationUpdated:
48                                 updateConversationIds.add(key)
49
50                 if updateConversationIds:
51                         message = (self, updateConversationIds, )
52                         self.updateSignalHandler.stage.send(message)
53
54         def get_conversations(self):
55                 return self._conversations.iterkeys()
56
57         def get_conversation(self, key):
58                 return self._conversations[key]
59
60         def clear_conversation(self, key):
61                 try:
62                         del self._conversations[key]
63                 except KeyError:
64                         _moduleLogger.info("Conversation never existed for %r" % (key,))
65
66         def clear_all(self):
67                 self._conversations.clear()
68
69
70 class Conversation(object):
71
72         def __init__(self, backend, data):
73                 self._backend = backend
74                 self._data = dict((key, value) for (key, value) in data.iteritems())
75
76                 # confirm we have a list
77                 self._data["messageParts"] = list(
78                         self._append_time(message, self._data["time"])
79                         for message in self._data["messageParts"]
80                 )
81
82         def __getitem__(self, key):
83                 return self._data[key]
84
85         def merge_conversation(self, moreData):
86                 """
87                 @returns True if there was content to merge (new messages arrived
88                 rather than being a duplicate)
89
90                 @warning This assumes merges are done in chronological order
91                 """
92                 for constantField in ("contactId", "number"):
93                         assert self._data[constantField] == moreData[constantField], "Constant field changed, soemthing is seriously messed up: %r v %r" % (self._data, moreData)
94
95                 if moreData["time"] < self._data["time"]:
96                         # If its older, assuming it has nothing new to report
97                         return False
98
99                 for preferredMoreField in ("id", "name", "time", "relTime", "prettyNumber", "location"):
100                         preferredFieldValue = moreData[preferredMoreField]
101                         if preferredFieldValue:
102                                 self._data[preferredMoreField] = preferredFieldValue
103
104                 messageAppended = False
105
106                 # @todo Handle No Transcription voicemails
107                 messageParts = self._data["messageParts"]
108                 for message in moreData["messageParts"]:
109                         messageWithTimestamp = self._append_time(message, moreData["time"])
110                         if messageWithTimestamp not in messageParts:
111                                 messageParts.append(messageWithTimestamp)
112                                 messageAppended = True
113                 messageParts.sort()
114
115                 return messageAppended
116
117         @staticmethod
118         def _append_time(message, exactWhen):
119                 whoFrom, message, when = message
120                 return exactWhen, whoFrom, message, when