Massive reworking of messages to make debugging easier along with some code cleaning...
[theonering] / src / gvoice / conversations.py
1 #!/usr/bin/python
2
3
4 import logging
5
6 import util.coroutines as coroutines
7
8
9 _moduleLogger = logging.getLogger("gvoice.conversations")
10
11
12 class Conversations(object):
13
14         def __init__(self, backend):
15                 self._backend = backend
16                 self._conversations = {}
17
18                 self.updateSignalHandler = coroutines.CoTee()
19
20         def update(self, force=False):
21                 if not force and self._conversations:
22                         return
23
24                 oldConversationIds = set(self._conversations.iterkeys())
25
26                 updateConversationIds = set()
27                 conversations = list(self._backend.get_conversations())
28                 conversations.sort()
29                 for conversation in conversations:
30                         key = conversation.contactId, conversation.number
31                         try:
32                                 mergedConversations = self._conversations[key]
33                         except KeyError:
34                                 mergedConversations = MergedConversations()
35                                 self._conversations[key] = mergedConversations
36
37                         try:
38                                 mergedConversations.append_conversation(conversation)
39                                 isConversationUpdated = True
40                         except RuntimeError:
41                                 isConversationUpdated = False
42
43                         if isConversationUpdated:
44                                 updateConversationIds.add(key)
45
46                 if updateConversationIds:
47                         message = (self, updateConversationIds, )
48                         self.updateSignalHandler.stage.send(message)
49
50         def get_conversations(self):
51                 return self._conversations.iterkeys()
52
53         def get_conversation(self, key):
54                 return self._conversations[key]
55
56         def clear_conversation(self, key):
57                 try:
58                         del self._conversations[key]
59                 except KeyError:
60                         _moduleLogger.info("Conversation never existed for %r" % (key,))
61
62         def clear_all(self):
63                 self._conversations.clear()
64
65
66 class MergedConversations(object):
67
68         def __init__(self):
69                 self._conversations = []
70
71         def append_conversation(self, newConversation):
72                 self._validate(newConversation)
73                 self._remove_repeats(newConversation)
74                 self._conversations.append(newConversation)
75
76         @property
77         def conversations(self):
78                 return self._conversations
79
80         def _validate(self, newConversation):
81                 if not self._conversations:
82                         return
83
84                 for constantField in ("contactId", "number"):
85                         assert getattr(self._conversations[0], constantField) == getattr(newConversation, constantField), "Constant field changed, soemthing is seriously messed up: %r v %r" % (
86                                 getattr(self._conversations[0], constantField),
87                                 getattr(newConversation, constantField),
88                         )
89
90                 if newConversation.time <= self._conversations[-1].time:
91                         raise RuntimeError("Conversations got out of order")
92
93         def _remove_repeats(self, newConversation):
94                 similarConversations = [
95                         conversation
96                         for conversation in self._conversations
97                         if conversation.id == newConversation.id
98                 ]
99
100                 for similarConversation in similarConversations:
101                         for commonField in ("isRead", "isSpam", "isTrash", "isArchived"):
102                                 newValue = getattr(newConversation, commonField)
103                                 setattr(similarConversation, commonField, newValue)
104
105                         newConversation.messages = [
106                                 newMessage
107                                 for newMessage in newConversation.messages
108                                 if newMessage not in similarConversation.messages
109                         ]
110                         assert 0 < len(newConversation.messages), "Everything shouldn't have been removed"