Merge lp:~phablet-team/history-service/optimize_dbus_traffic into lp:history-service/staging
- optimize_dbus_traffic
- Merge into staging
Proposed by
Gustavo Pichorim Boiko
Status: | Merged |
---|---|
Approved by: | Tiago Salem Herrmann |
Approved revision: | 275 |
Merged at revision: | 261 |
Proposed branch: | lp:~phablet-team/history-service/optimize_dbus_traffic |
Merge into: | lp:history-service/staging |
Prerequisite: | lp:~phablet-team/history-service/sort_by_multiple_fields |
Diff against target: |
884 lines (+279/-210) 19 files modified
Ubuntu/History/historyeventmodel.cpp (+19/-33) Ubuntu/History/historyeventmodel.h (+2/-5) Ubuntu/History/historymodel.cpp (+79/-5) Ubuntu/History/historymodel.h (+10/-0) Ubuntu/History/historythreadmodel.cpp (+0/-19) Ubuntu/History/historythreadmodel.h (+0/-1) daemon/historydaemon.cpp (+41/-76) daemon/historydaemon.h (+2/-1) daemon/historyservicedbus.cpp (+83/-7) daemon/historyservicedbus.h (+15/-0) daemon/textchannelobserver.cpp (+0/-14) daemon/textchannelobserver.h (+0/-2) plugins/sqlite/schema/v18.sql (+14/-0) plugins/sqlite/sqlitehistoryplugin.cpp (+2/-2) src/eventview.cpp (+5/-1) src/eventview.h (+3/-1) src/managerdbus.cpp (+3/-10) tests/Ubuntu.History/HistoryEventModelTest.cpp (+1/-1) tests/libhistoryservice/ManagerTest.cpp (+0/-32) |
To merge this branch: | bzr merge lp:~phablet-team/history-service/optimize_dbus_traffic |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tiago Salem Herrmann (community) | Approve | ||
Review via email: mp+317649@code.launchpad.net |
Commit message
Reduce the dbus traffic when marking messages and threads as read.
Description of the change
Reduce the dbus traffic when marking messages and threads as read.
To post a comment you must log in.
- 266. By Gustavo Pichorim Boiko
-
Only update the new events
- 267. By Tiago Salem Herrmann
-
merge parent branch
- 268. By Tiago Salem Herrmann
-
fix build
- 269. By Gustavo Pichorim Boiko
-
Stop using the telepathy pending message status to mark messages as read as
that causes performance problems when dealing with a large number of messages. - 270. By Gustavo Pichorim Boiko
-
Optimize thread removal by deleting the events using a sqlite trigger instead
of manually removing and notifying them.
Also make the thread and event removal asynchronous calls on dbus level as the
result will be notified back to us as signals. - 271. By Gustavo Pichorim Boiko
-
Update tests
- 272. By Gustavo Pichorim Boiko
-
When threads are removed, make sure the events models get refreshed accordingly.
- 273. By Tiago Salem Herrmann
-
merge parent branch
- 274. By Tiago Salem Herrmann
-
revert wrong commit
- 275. By Gustavo Pichorim Boiko
-
Remove debugs
Revision history for this message
Tiago Salem Herrmann (tiagosh) wrote : | # |
looks good. thanks
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'Ubuntu/History/historyeventmodel.cpp' |
2 | --- Ubuntu/History/historyeventmodel.cpp 2017-03-22 20:18:11 +0000 |
3 | +++ Ubuntu/History/historyeventmodel.cpp 2017-03-22 20:18:11 +0000 |
4 | @@ -1,5 +1,5 @@ |
5 | /* |
6 | - * Copyright (C) 2013-2015 Canonical, Ltd. |
7 | + * Copyright (C) 2013-2017 Canonical, Ltd. |
8 | * |
9 | * Authors: |
10 | * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com> |
11 | @@ -29,7 +29,7 @@ |
12 | #include <QTimerEvent> |
13 | |
14 | HistoryEventModel::HistoryEventModel(QObject *parent) : |
15 | - HistoryModel(parent), mCanFetchMore(true), mEventWritingTimer(0) |
16 | + HistoryModel(parent), mCanFetchMore(true) |
17 | { |
18 | // configure the roles |
19 | mRoles = HistoryModel::roleNames(); |
20 | @@ -318,23 +318,6 @@ |
21 | return History::Manager::instance()->writeEvents(History::Events() << textEvent); |
22 | } |
23 | |
24 | -bool HistoryEventModel::markEventAsRead(const QString &accountId, const QString &threadId, const QString &eventId, int eventType) |
25 | -{ |
26 | - History::Event event = History::Manager::instance()->getSingleEvent((History::EventType)eventType, accountId, threadId, eventId); |
27 | - event.setNewEvent(false); |
28 | - if (event.type() == History::EventTypeText) { |
29 | - History::TextEvent textEvent = event; |
30 | - textEvent.setReadTimestamp(QDateTime::currentDateTime()); |
31 | - event = textEvent; |
32 | - } |
33 | - mEventWritingQueue << event; |
34 | - if (mEventWritingTimer != 0) { |
35 | - killTimer(mEventWritingTimer); |
36 | - } |
37 | - mEventWritingTimer = startTimer(500); |
38 | - return true; |
39 | -} |
40 | - |
41 | void HistoryEventModel::updateQuery() |
42 | { |
43 | // remove all events from the model |
44 | @@ -374,6 +357,9 @@ |
45 | SIGNAL(eventsRemoved(History::Events)), |
46 | SLOT(onEventsRemoved(History::Events))); |
47 | connect(mView.data(), |
48 | + SIGNAL(threadsRemoved(History::Threads)), |
49 | + SLOT(onThreadsRemoved(History::Threads))); |
50 | + connect(mView.data(), |
51 | SIGNAL(invalidated()), |
52 | SLOT(triggerQueryUpdate())); |
53 | |
54 | @@ -450,21 +436,21 @@ |
55 | // should be handle internally in History::EventView? |
56 | } |
57 | |
58 | -void HistoryEventModel::timerEvent(QTimerEvent *event) |
59 | +void HistoryEventModel::onThreadsRemoved(const History::Threads &threads) |
60 | { |
61 | - HistoryModel::timerEvent(event); |
62 | - if (event->timerId() == mEventWritingTimer) { |
63 | - killTimer(mEventWritingTimer); |
64 | - mEventWritingTimer = 0; |
65 | - |
66 | - if (mEventWritingQueue.isEmpty()) { |
67 | - return; |
68 | - } |
69 | - |
70 | - qDebug() << "Goint to update" << mEventWritingQueue.count() << "events."; |
71 | - if (History::Manager::instance()->writeEvents(mEventWritingQueue)) { |
72 | - qDebug() << "... succeeded!"; |
73 | - mEventWritingQueue.clear(); |
74 | + // When a thread is removed we don't get event removed signals, |
75 | + // so we compare and find if we have an event matching that thread. |
76 | + // in case we find it, we invalidate the whole view as there might be |
77 | + // out of date cached data on the daemon side |
78 | + int count = rowCount(); |
79 | + Q_FOREACH(const History::Thread &thread, threads) { |
80 | + for (int i = 0; i < count; ++i) { |
81 | + QModelIndex idx = index(i); |
82 | + if (idx.data(AccountIdRole).toString() == thread.accountId() && |
83 | + idx.data(ThreadIdRole).toString() == thread.threadId()) { |
84 | + triggerQueryUpdate(); |
85 | + return; |
86 | + } |
87 | } |
88 | } |
89 | } |
90 | |
91 | === modified file 'Ubuntu/History/historyeventmodel.h' |
92 | --- Ubuntu/History/historyeventmodel.h 2016-09-16 12:32:37 +0000 |
93 | +++ Ubuntu/History/historyeventmodel.h 2017-03-22 20:18:11 +0000 |
94 | @@ -1,5 +1,5 @@ |
95 | /* |
96 | - * Copyright (C) 2013-2015 Canonical, Ltd. |
97 | + * Copyright (C) 2013-2017 Canonical, Ltd. |
98 | * |
99 | * Authors: |
100 | * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com> |
101 | @@ -66,7 +66,6 @@ |
102 | |
103 | Q_INVOKABLE bool removeEvents(const QVariantList &eventsProperties); |
104 | Q_INVOKABLE bool writeEvents(const QVariantList &eventsProperties); |
105 | - Q_INVOKABLE bool markEventAsRead(const QString &accountId, const QString &threadId, const QString &eventId, int eventType); |
106 | Q_INVOKABLE bool removeEventAttachment(const QString &accountId, const QString &threadId, const QString &eventId, int eventType, const QString &attachmentId); |
107 | |
108 | protected Q_SLOTS: |
109 | @@ -74,9 +73,9 @@ |
110 | virtual void onEventsAdded(const History::Events &events); |
111 | virtual void onEventsModified(const History::Events &events); |
112 | virtual void onEventsRemoved(const History::Events &events); |
113 | + virtual void onThreadsRemoved(const History::Threads &threads); |
114 | |
115 | protected: |
116 | - void timerEvent(QTimerEvent *event); |
117 | History::Events fetchNextPage(); |
118 | |
119 | private: |
120 | @@ -85,8 +84,6 @@ |
121 | bool mCanFetchMore; |
122 | QHash<int, QByteArray> mRoles; |
123 | mutable QMap<History::TextEvent, QList<QVariant> > mAttachmentCache; |
124 | - History::Events mEventWritingQueue; |
125 | - int mEventWritingTimer; |
126 | }; |
127 | |
128 | #endif // HISTORYEVENTMODEL_H |
129 | |
130 | === modified file 'Ubuntu/History/historymodel.cpp' |
131 | --- Ubuntu/History/historymodel.cpp 2017-03-22 20:18:11 +0000 |
132 | +++ Ubuntu/History/historymodel.cpp 2017-03-22 20:18:11 +0000 |
133 | @@ -28,13 +28,14 @@ |
134 | #include "textevent.h" |
135 | #include "manager.h" |
136 | #include "utils_p.h" |
137 | +#include "voiceevent.h" |
138 | #include <QTimerEvent> |
139 | #include <QCryptographicHash> |
140 | #include <QDebug> |
141 | |
142 | HistoryModel::HistoryModel(QObject *parent) : |
143 | QAbstractListModel(parent), mFilter(0), mSort(new HistoryQmlSort(this)), |
144 | - mType(EventTypeText), mMatchContacts(false), mUpdateTimer(0), mWaitingForQml(false) |
145 | + mType(EventTypeText), mMatchContacts(false), mUpdateTimer(0), mEventWritingTimer(0), mThreadWritingTimer(0), mWaitingForQml(false) |
146 | { |
147 | // configure the roles |
148 | mRoles[AccountIdRole] = "accountId"; |
149 | @@ -406,10 +407,33 @@ |
150 | |
151 | void HistoryModel::timerEvent(QTimerEvent *event) |
152 | { |
153 | - if (event->timerId() == mUpdateTimer && !mWaitingForQml) { |
154 | - killTimer(mUpdateTimer); |
155 | - mUpdateTimer = 0; |
156 | - updateQuery(); |
157 | + if (event->timerId() == mUpdateTimer) { |
158 | + if (!mWaitingForQml) { |
159 | + killTimer(mUpdateTimer); |
160 | + mUpdateTimer = 0; |
161 | + updateQuery(); |
162 | + } |
163 | + } else if (event->timerId() == mEventWritingTimer) { |
164 | + killTimer(mEventWritingTimer); |
165 | + mEventWritingTimer = 0; |
166 | + |
167 | + if (mEventWritingQueue.isEmpty()) { |
168 | + return; |
169 | + } |
170 | + |
171 | + if (History::Manager::instance()->writeEvents(mEventWritingQueue)) { |
172 | + mEventWritingQueue.clear(); |
173 | + } |
174 | + } else if (event->timerId() == mThreadWritingTimer) { |
175 | + killTimer(mThreadWritingTimer); |
176 | + mThreadWritingTimer = 0; |
177 | + |
178 | + if (mThreadWritingQueue.isEmpty()) { |
179 | + return; |
180 | + } |
181 | + |
182 | + History::Manager::instance()->markThreadsAsRead(mThreadWritingQueue); |
183 | + mThreadWritingQueue.clear(); |
184 | } |
185 | } |
186 | |
187 | @@ -478,6 +502,56 @@ |
188 | return data; |
189 | } |
190 | |
191 | +bool HistoryModel::markEventAsRead(const QVariantMap &eventProperties) |
192 | +{ |
193 | + History::Event event; |
194 | + History::EventType type = (History::EventType) eventProperties[History::FieldType].toInt(); |
195 | + switch (type) { |
196 | + case History::EventTypeText: |
197 | + event = History::TextEvent::fromProperties(eventProperties); |
198 | + break; |
199 | + case History::EventTypeVoice: |
200 | + event = History::VoiceEvent::fromProperties(eventProperties); |
201 | + break; |
202 | + } |
203 | + |
204 | + event.setNewEvent(false); |
205 | + if (event.type() == History::EventTypeText) { |
206 | + History::TextEvent textEvent = event; |
207 | + textEvent.setReadTimestamp(QDateTime::currentDateTime()); |
208 | + event = textEvent; |
209 | + } |
210 | + // for repeated events, keep the last called one only |
211 | + if (mEventWritingQueue.contains(event)) { |
212 | + mEventWritingQueue.removeOne(event); |
213 | + } |
214 | + mEventWritingQueue << event; |
215 | + if (mEventWritingTimer != 0) { |
216 | + killTimer(mEventWritingTimer); |
217 | + } |
218 | + mEventWritingTimer = startTimer(500); |
219 | + return true; |
220 | +} |
221 | + |
222 | +void HistoryModel::markThreadsAsRead(const QVariantList &threadsProperties) |
223 | +{ |
224 | + Q_FOREACH(const QVariant &entry, threadsProperties) { |
225 | + QVariantMap threadProperties = entry.toMap(); |
226 | + History::Thread thread = History::Thread::fromProperties(threadProperties); |
227 | + if (!thread.isNull()) { |
228 | + if (mThreadWritingQueue.contains(thread)) { |
229 | + continue; |
230 | + } |
231 | + mThreadWritingQueue << thread; |
232 | + } |
233 | + } |
234 | + |
235 | + if (mThreadWritingTimer != 0) { |
236 | + killTimer(mThreadWritingTimer); |
237 | + } |
238 | + mThreadWritingTimer = startTimer(2000); |
239 | +} |
240 | + |
241 | void HistoryModel::classBegin() |
242 | { |
243 | mWaitingForQml = true; |
244 | |
245 | === modified file 'Ubuntu/History/historymodel.h' |
246 | --- Ubuntu/History/historymodel.h 2016-11-09 17:42:27 +0000 |
247 | +++ Ubuntu/History/historymodel.h 2017-03-22 20:18:11 +0000 |
248 | @@ -23,6 +23,8 @@ |
249 | #define HISTORYMODEL_H |
250 | |
251 | #include "types.h" |
252 | +#include "event.h" |
253 | +#include "thread.h" |
254 | #include "historyqmlfilter.h" |
255 | #include "historyqmlsort.h" |
256 | #include <QAbstractListModel> |
257 | @@ -175,6 +177,10 @@ |
258 | |
259 | Q_INVOKABLE virtual QVariant get(int row) const; |
260 | |
261 | + // Marking events and threads as read |
262 | + Q_INVOKABLE bool markEventAsRead(const QVariantMap &eventProperties); |
263 | + Q_INVOKABLE void markThreadsAsRead(const QVariantList &threadsProperties); |
264 | + |
265 | // QML parser status things |
266 | void classBegin(); |
267 | void componentComplete(); |
268 | @@ -206,6 +212,10 @@ |
269 | |
270 | private: |
271 | QHash<int, QByteArray> mRoles; |
272 | + History::Events mEventWritingQueue; |
273 | + int mEventWritingTimer; |
274 | + History::Threads mThreadWritingQueue; |
275 | + int mThreadWritingTimer; |
276 | int mUpdateTimer; |
277 | bool mWaitingForQml; |
278 | }; |
279 | |
280 | === modified file 'Ubuntu/History/historythreadmodel.cpp' |
281 | --- Ubuntu/History/historythreadmodel.cpp 2017-03-22 20:18:11 +0000 |
282 | +++ Ubuntu/History/historythreadmodel.cpp 2017-03-22 20:18:11 +0000 |
283 | @@ -232,25 +232,6 @@ |
284 | return mRoles; |
285 | } |
286 | |
287 | -void HistoryThreadModel::markThreadsAsRead(const QVariantList &threadsProperties) |
288 | -{ |
289 | - History::Threads threads; |
290 | - Q_FOREACH(const QVariant &entry, threadsProperties) { |
291 | - QVariantMap threadProperties = entry.toMap(); |
292 | - History::Thread thread = History::Thread::fromProperties(threadProperties); |
293 | - |
294 | - if (!thread.isNull()) { |
295 | - threads << thread; |
296 | - } |
297 | - } |
298 | - |
299 | - if (threads.isEmpty()) { |
300 | - return; |
301 | - } |
302 | - |
303 | - History::Manager::instance()->markThreadsAsRead(threads); |
304 | -} |
305 | - |
306 | bool HistoryThreadModel::removeThreads(const QVariantList &threadsProperties) |
307 | { |
308 | History::Threads threads; |
309 | |
310 | === modified file 'Ubuntu/History/historythreadmodel.h' |
311 | --- Ubuntu/History/historythreadmodel.h 2017-03-22 20:18:11 +0000 |
312 | +++ Ubuntu/History/historythreadmodel.h 2017-03-22 20:18:11 +0000 |
313 | @@ -70,7 +70,6 @@ |
314 | virtual QHash<int, QByteArray> roleNames() const; |
315 | |
316 | Q_INVOKABLE bool removeThreads(const QVariantList &threadsProperties); |
317 | - Q_INVOKABLE void markThreadsAsRead(const QVariantList &threadsProperties); |
318 | |
319 | protected Q_SLOTS: |
320 | virtual void updateQuery(); |
321 | |
322 | === modified file 'daemon/historydaemon.cpp' |
323 | --- daemon/historydaemon.cpp 2017-03-22 20:18:11 +0000 |
324 | +++ daemon/historydaemon.cpp 2017-03-22 20:18:11 +0000 |
325 | @@ -140,9 +140,6 @@ |
326 | SIGNAL(messageSent(Tp::TextChannelPtr,Tp::Message,QString)), |
327 | SLOT(onMessageSent(Tp::TextChannelPtr,Tp::Message,QString))); |
328 | connect(&mTextObserver, |
329 | - SIGNAL(messageRead(Tp::TextChannelPtr,Tp::ReceivedMessage)), |
330 | - SLOT(onMessageRead(Tp::TextChannelPtr,Tp::ReceivedMessage))); |
331 | - connect(&mTextObserver, |
332 | SIGNAL(channelAvailable(Tp::TextChannelPtr)), |
333 | SLOT(onTextChannelAvailable(Tp::TextChannelPtr))); |
334 | connect(&mTextObserver, |
335 | @@ -590,38 +587,17 @@ |
336 | return false; |
337 | } |
338 | |
339 | - // In order to remove a thread all we have to do is to remove all its items |
340 | - // then it is going to be removed by removeEvents() once it detects the thread is |
341 | - // empty. |
342 | - QList<QVariantMap> events; |
343 | - QMap<QString, QVariantMap> removedEmptyThreads; |
344 | + // If the thread has events |
345 | + mBackend->beginBatchOperation(); |
346 | Q_FOREACH(const QVariantMap &thread, threads) { |
347 | - QList<QVariantMap> thisEvents = mBackend->eventsForThread(thread); |
348 | - if (thisEvents.isEmpty()) { |
349 | - mBackend->beginBatchOperation(); |
350 | - if (!mBackend->removeThread(thread)) { |
351 | - mBackend->rollbackBatchOperation(); |
352 | - return false; |
353 | - } |
354 | - mBackend->endBatchOperation(); |
355 | - QString hash = hashThread(thread); |
356 | - removedEmptyThreads[hash] = thread; |
357 | - continue; |
358 | - } |
359 | - events += thisEvents; |
360 | - } |
361 | - |
362 | - if (!removedEmptyThreads.isEmpty()) { |
363 | - mDBus.notifyThreadsRemoved(removedEmptyThreads.values()); |
364 | - } |
365 | - |
366 | - if (events.size() > 0) { |
367 | - if(removeEvents(events)) { |
368 | - return true; |
369 | - } |
370 | - } |
371 | - |
372 | - return false; |
373 | + if (!mBackend->removeThread(thread)) { |
374 | + mBackend->rollbackBatchOperation(); |
375 | + return false; |
376 | + } |
377 | + } |
378 | + mBackend->endBatchOperation(); |
379 | + mDBus.notifyThreadsRemoved(threads); |
380 | + return true; |
381 | } |
382 | |
383 | void HistoryDaemon::onObserverCreated() |
384 | @@ -1039,32 +1015,7 @@ |
385 | return; |
386 | } |
387 | |
388 | - History::MessageStatus status; |
389 | - switch (message.deliveryDetails().status()) { |
390 | - case Tp::DeliveryStatusAccepted: |
391 | - status = History::MessageStatusAccepted; |
392 | - break; |
393 | - case Tp::DeliveryStatusDeleted: |
394 | - status = History::MessageStatusDeleted; |
395 | - break; |
396 | - case Tp::DeliveryStatusDelivered: |
397 | - status = History::MessageStatusDelivered; |
398 | - break; |
399 | - case Tp::DeliveryStatusPermanentlyFailed: |
400 | - status = History::MessageStatusPermanentlyFailed; |
401 | - break; |
402 | - case Tp::DeliveryStatusRead: |
403 | - status = History::MessageStatusRead; |
404 | - break; |
405 | - case Tp::DeliveryStatusTemporarilyFailed: |
406 | - status = History::MessageStatusTemporarilyFailed; |
407 | - break; |
408 | - case Tp::DeliveryStatusUnknown: |
409 | - status = History::MessageStatusUnknown; |
410 | - break; |
411 | - } |
412 | - |
413 | - textEvent[History::FieldMessageStatus] = (int) status; |
414 | + textEvent[History::FieldMessageStatus] = (int) fromTelepathyDeliveryStatus(message.deliveryDetails().status()); |
415 | if (!writeEvents(QList<QVariantMap>() << textEvent, properties)) { |
416 | qWarning() << "Failed to save the new message status!"; |
417 | } |
418 | @@ -1176,22 +1127,6 @@ |
419 | |
420 | } |
421 | |
422 | -void HistoryDaemon::onMessageRead(const Tp::TextChannelPtr textChannel, const Tp::ReceivedMessage &message) |
423 | -{ |
424 | - QVariantMap textEvent = getSingleEventFromTextChannel(textChannel, message.messageToken()); |
425 | - QVariantMap properties = propertiesFromChannel(textChannel); |
426 | - |
427 | - if (textEvent.isEmpty()) { |
428 | - qWarning() << "Cound not find the original event to update with newEvent = false."; |
429 | - return; |
430 | - } |
431 | - |
432 | - textEvent[History::FieldNewEvent] = false; |
433 | - if (!writeEvents(QList<QVariantMap>() << textEvent, properties)) { |
434 | - qWarning() << "Failed to save the new message status!"; |
435 | - } |
436 | -} |
437 | - |
438 | void HistoryDaemon::onMessageSent(const Tp::TextChannelPtr textChannel, const Tp::Message &message, const QString &messageToken) |
439 | { |
440 | QVariantMap properties = propertiesFromChannel(textChannel); |
441 | @@ -1383,3 +1318,33 @@ |
442 | } |
443 | } |
444 | } |
445 | + |
446 | +History::MessageStatus HistoryDaemon::fromTelepathyDeliveryStatus(Tp::DeliveryStatus deliveryStatus) |
447 | +{ |
448 | + History::MessageStatus status; |
449 | + switch (deliveryStatus) { |
450 | + case Tp::DeliveryStatusAccepted: |
451 | + status = History::MessageStatusAccepted; |
452 | + break; |
453 | + case Tp::DeliveryStatusDeleted: |
454 | + status = History::MessageStatusDeleted; |
455 | + break; |
456 | + case Tp::DeliveryStatusDelivered: |
457 | + status = History::MessageStatusDelivered; |
458 | + break; |
459 | + case Tp::DeliveryStatusPermanentlyFailed: |
460 | + status = History::MessageStatusPermanentlyFailed; |
461 | + break; |
462 | + case Tp::DeliveryStatusRead: |
463 | + status = History::MessageStatusRead; |
464 | + break; |
465 | + case Tp::DeliveryStatusTemporarilyFailed: |
466 | + status = History::MessageStatusTemporarilyFailed; |
467 | + break; |
468 | + case Tp::DeliveryStatusUnknown: |
469 | + status = History::MessageStatusUnknown; |
470 | + break; |
471 | + } |
472 | + |
473 | + return status; |
474 | +} |
475 | |
476 | === modified file 'daemon/historydaemon.h' |
477 | --- daemon/historydaemon.h 2017-03-22 20:18:11 +0000 |
478 | +++ daemon/historydaemon.h 2017-03-22 20:18:11 +0000 |
479 | @@ -68,7 +68,6 @@ |
480 | void onObserverCreated(); |
481 | void onCallEnded(const Tp::CallChannelPtr &channel, bool missed); |
482 | void onMessageReceived(const Tp::TextChannelPtr textChannel, const Tp::ReceivedMessage &message); |
483 | - void onMessageRead(const Tp::TextChannelPtr textChannel, const Tp::ReceivedMessage &message); |
484 | void onMessageSent(const Tp::TextChannelPtr textChannel, const Tp::Message &message, const QString &messageToken); |
485 | void onTextChannelAvailable(const Tp::TextChannelPtr channel); |
486 | void onTextChannelInvalidated(const Tp::TextChannelPtr channel); |
487 | @@ -92,6 +91,8 @@ |
488 | void writeRoomChangesInformationEvents(const QVariantMap &thread, const QVariantMap &interfaceProperties); |
489 | void writeRolesInformationEvents(const QVariantMap &thread, const Tp::ChannelPtr &channel, const RolesMap &rolesMap); |
490 | void writeRolesChangesInformationEvents(const QVariantMap &thread, const Tp::ChannelPtr &channel, const RolesMap &rolesMap); |
491 | + |
492 | + static History::MessageStatus fromTelepathyDeliveryStatus(Tp::DeliveryStatus deliveryStatus); |
493 | private: |
494 | HistoryDaemon(QObject *parent = 0); |
495 | |
496 | |
497 | === modified file 'daemon/historyservicedbus.cpp' |
498 | --- daemon/historyservicedbus.cpp 2017-03-22 20:18:11 +0000 |
499 | +++ daemon/historyservicedbus.cpp 2017-03-22 20:18:11 +0000 |
500 | @@ -27,7 +27,7 @@ |
501 | Q_DECLARE_METATYPE(QList< QVariantMap >) |
502 | |
503 | HistoryServiceDBus::HistoryServiceDBus(QObject *parent) : |
504 | - QObject(parent), mAdaptor(0) |
505 | + QObject(parent), mAdaptor(0), mSignalsTimer(-1) |
506 | { |
507 | qDBusRegisterMetaType<QList<QVariantMap> >(); |
508 | } |
509 | @@ -47,32 +47,38 @@ |
510 | |
511 | void HistoryServiceDBus::notifyThreadsAdded(const QList<QVariantMap> &threads) |
512 | { |
513 | - Q_EMIT ThreadsAdded(threads); |
514 | + mThreadsAdded << threads; |
515 | + triggerSignals(); |
516 | } |
517 | |
518 | void HistoryServiceDBus::notifyThreadsModified(const QList<QVariantMap> &threads) |
519 | { |
520 | - Q_EMIT ThreadsModified(threads); |
521 | + mThreadsModified << threads; |
522 | + triggerSignals(); |
523 | } |
524 | |
525 | void HistoryServiceDBus::notifyThreadsRemoved(const QList<QVariantMap> &threads) |
526 | { |
527 | - Q_EMIT ThreadsRemoved(threads); |
528 | + mThreadsRemoved << threads; |
529 | + triggerSignals(); |
530 | } |
531 | |
532 | void HistoryServiceDBus::notifyEventsAdded(const QList<QVariantMap> &events) |
533 | { |
534 | - Q_EMIT EventsAdded(events); |
535 | + mEventsAdded << events; |
536 | + triggerSignals(); |
537 | } |
538 | |
539 | void HistoryServiceDBus::notifyEventsModified(const QList<QVariantMap> &events) |
540 | { |
541 | - Q_EMIT EventsModified(events); |
542 | + mEventsModified << events; |
543 | + triggerSignals(); |
544 | } |
545 | |
546 | void HistoryServiceDBus::notifyEventsRemoved(const QList<QVariantMap> &events) |
547 | { |
548 | - Q_EMIT EventsRemoved(events); |
549 | + mEventsRemoved << events; |
550 | + triggerSignals(); |
551 | } |
552 | |
553 | void HistoryServiceDBus::notifyThreadParticipantsChanged(const QVariantMap &thread, |
554 | @@ -152,3 +158,73 @@ |
555 | return HistoryDaemon::instance()->getSingleEvent(type, accountId, threadId, eventId); |
556 | } |
557 | |
558 | +void HistoryServiceDBus::timerEvent(QTimerEvent *event) |
559 | +{ |
560 | + if (event->timerId() == mSignalsTimer) { |
561 | + killTimer(mSignalsTimer); |
562 | + mSignalsTimer = -1; |
563 | + processSignals(); |
564 | + } |
565 | +} |
566 | + |
567 | +void HistoryServiceDBus::filterDuplicatesAndAdd(QList<QVariantMap> &targetList, const QList<QVariantMap> newItems, const QStringList &propertiesToCompare) |
568 | +{ |
569 | + Q_FOREACH (const QVariantMap &item, newItems) { |
570 | + Q_FOREACH(const QVariantMap &existing, targetList) { |
571 | + bool found = true; |
572 | + Q_FOREACH(const QString &prop, propertiesToCompare) { |
573 | + if (item[prop] != existing[prop]) { |
574 | + found = false; |
575 | + break; |
576 | + } |
577 | + } |
578 | + |
579 | + if (!found) { |
580 | + targetList << item; |
581 | + } |
582 | + } |
583 | + } |
584 | +} |
585 | + |
586 | +void HistoryServiceDBus::triggerSignals() |
587 | +{ |
588 | + if (mSignalsTimer >= 0) { |
589 | + killTimer(mSignalsTimer); |
590 | + } |
591 | + |
592 | + mSignalsTimer = startTimer(100); |
593 | +} |
594 | + |
595 | +void HistoryServiceDBus::processSignals() |
596 | +{ |
597 | + if (!mThreadsAdded.isEmpty()) { |
598 | + Q_EMIT ThreadsAdded(mThreadsAdded); |
599 | + mThreadsAdded.clear(); |
600 | + } |
601 | + |
602 | + if (!mThreadsModified.isEmpty()) { |
603 | + Q_EMIT ThreadsModified(mThreadsModified); |
604 | + mThreadsModified.clear(); |
605 | + } |
606 | + |
607 | + if (!mThreadsRemoved.isEmpty()) { |
608 | + Q_EMIT ThreadsRemoved(mThreadsRemoved); |
609 | + mThreadsRemoved.clear(); |
610 | + } |
611 | + |
612 | + if (!mEventsAdded.isEmpty()) { |
613 | + Q_EMIT EventsAdded(mEventsAdded); |
614 | + mEventsAdded.clear(); |
615 | + } |
616 | + |
617 | + if (!mEventsModified.isEmpty()) { |
618 | + Q_EMIT EventsModified(mEventsModified); |
619 | + mEventsModified.clear(); |
620 | + } |
621 | + |
622 | + if (!mEventsRemoved.isEmpty()) { |
623 | + Q_EMIT EventsRemoved(mEventsRemoved); |
624 | + mEventsRemoved.clear(); |
625 | + } |
626 | +} |
627 | + |
628 | |
629 | === modified file 'daemon/historyservicedbus.h' |
630 | --- daemon/historyservicedbus.h 2017-03-22 20:18:11 +0000 |
631 | +++ daemon/historyservicedbus.h 2017-03-22 20:18:11 +0000 |
632 | @@ -84,8 +84,23 @@ |
633 | void EventsModified(const QList<QVariantMap> &events); |
634 | void EventsRemoved(const QList<QVariantMap> &events); |
635 | |
636 | +protected: |
637 | + void timerEvent(QTimerEvent *event) override; |
638 | + |
639 | +protected Q_SLOTS: |
640 | + void filterDuplicatesAndAdd(QList<QVariantMap> &targetList, const QList<QVariantMap> newItems, const QStringList &propertiesToCompare); |
641 | + void triggerSignals(); |
642 | + void processSignals(); |
643 | + |
644 | private: |
645 | HistoryServiceAdaptor *mAdaptor; |
646 | + QList<QVariantMap> mThreadsAdded; |
647 | + QList<QVariantMap> mThreadsModified; |
648 | + QList<QVariantMap> mThreadsRemoved; |
649 | + QList<QVariantMap> mEventsAdded; |
650 | + QList<QVariantMap> mEventsModified; |
651 | + QList<QVariantMap> mEventsRemoved; |
652 | + int mSignalsTimer; |
653 | }; |
654 | |
655 | #endif // HISTORYSERVICEDBUS_H |
656 | |
657 | === modified file 'daemon/textchannelobserver.cpp' |
658 | --- daemon/textchannelobserver.cpp 2017-03-22 20:18:11 +0000 |
659 | +++ daemon/textchannelobserver.cpp 2017-03-22 20:18:11 +0000 |
660 | @@ -39,10 +39,6 @@ |
661 | connect(textChannel.data(), |
662 | SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString)), |
663 | SLOT(onMessageSent(Tp::Message,Tp::MessageSendingFlags,QString))); |
664 | - connect(textChannel.data(), |
665 | - SIGNAL(pendingMessageRemoved(const Tp::ReceivedMessage&)), |
666 | - SLOT(onPendingMessageRemoved(const Tp::ReceivedMessage&))); |
667 | - |
668 | Q_EMIT channelAvailable(textChannel); |
669 | |
670 | // process the messages that are already pending in the channel |
671 | @@ -83,13 +79,3 @@ |
672 | |
673 | Q_EMIT messageSent(textChannel, message, sentMessageToken); |
674 | } |
675 | - |
676 | -void TextChannelObserver::onPendingMessageRemoved(const Tp::ReceivedMessage &message) |
677 | -{ |
678 | - Tp::TextChannelPtr textChannel(qobject_cast<Tp::TextChannel*>(sender())); |
679 | - if (textChannel.isNull()) { |
680 | - return; |
681 | - } |
682 | - |
683 | - Q_EMIT messageRead(textChannel, message); |
684 | -} |
685 | |
686 | === modified file 'daemon/textchannelobserver.h' |
687 | --- daemon/textchannelobserver.h 2017-03-22 20:18:11 +0000 |
688 | +++ daemon/textchannelobserver.h 2017-03-22 20:18:11 +0000 |
689 | @@ -39,7 +39,6 @@ |
690 | void channelAvailable(const Tp::TextChannelPtr textChannel); |
691 | void textChannelInvalidated(const Tp::TextChannelPtr textChannel); |
692 | void messageReceived(const Tp::TextChannelPtr textChannel, const Tp::ReceivedMessage &message); |
693 | - void messageRead(const Tp::TextChannelPtr textChannel, const Tp::ReceivedMessage &message); |
694 | void messageSent(const Tp::TextChannelPtr textChannel, const Tp::Message &message, const QString &messageToken); |
695 | |
696 | protected: |
697 | @@ -50,7 +49,6 @@ |
698 | void onTextChannelInvalidated(); |
699 | void onMessageReceived(const Tp::ReceivedMessage &message); |
700 | void onMessageSent(const Tp::Message &message, Tp::MessageSendingFlags flags, const QString &sentMessageToken); |
701 | - void onPendingMessageRemoved(const Tp::ReceivedMessage &message); |
702 | |
703 | private: |
704 | QList<Tp::TextChannelPtr> mChannels; |
705 | |
706 | === added file 'plugins/sqlite/schema/v18.sql' |
707 | --- plugins/sqlite/schema/v18.sql 1970-01-01 00:00:00 +0000 |
708 | +++ plugins/sqlite/schema/v18.sql 2017-03-22 20:18:11 +0000 |
709 | @@ -0,0 +1,14 @@ |
710 | +CREATE TRIGGER text_threads_delete_trigger AFTER DELETE ON threads |
711 | +FOR EACH ROW WHEN old.type=0 |
712 | +BEGIN |
713 | + DELETE FROM text_events WHERE |
714 | + accountId=old.accountId AND |
715 | + threadId=old.threadId; |
716 | +END; |
717 | +CREATE TRIGGER voice_threads_delete_trigger AFTER DELETE ON threads |
718 | +FOR EACH ROW WHEN old.type=1 |
719 | +BEGIN |
720 | + DELETE FROM voice_events WHERE |
721 | + accountId=old.accountId AND |
722 | + threadId=old.threadId; |
723 | +END; |
724 | |
725 | === modified file 'plugins/sqlite/sqlitehistoryplugin.cpp' |
726 | --- plugins/sqlite/sqlitehistoryplugin.cpp 2017-03-22 20:18:11 +0000 |
727 | +++ plugins/sqlite/sqlitehistoryplugin.cpp 2017-03-22 20:18:11 +0000 |
728 | @@ -315,7 +315,7 @@ |
729 | return QVariantMap(); |
730 | } |
731 | |
732 | - query.prepare("UPDATE text_events SET newEvent=:newEvent WHERE accountId=:accountId AND threadId=:threadId"); |
733 | + query.prepare("UPDATE text_events SET newEvent=:newEvent WHERE accountId=:accountId AND threadId=:threadId AND newEvent=1"); |
734 | query.bindValue(":accountId", thread[History::FieldAccountId].toString()); |
735 | query.bindValue(":threadId", thread[History::FieldThreadId].toString()); |
736 | query.bindValue(":newEvent", false); |
737 | @@ -1337,7 +1337,7 @@ |
738 | chatRoomInfo["SelfRoles"] = query1.value(20).toInt(); |
739 | |
740 | thread[History::FieldChatRoomInfo] = chatRoomInfo; |
741 | - if (!History::Utils::shouldIncludeParticipants(thread)) { |
742 | + if (!History::Utils::shouldIncludeParticipants(History::Thread::fromProperties(thread))) { |
743 | thread.remove(History::FieldParticipants); |
744 | } |
745 | } |
746 | |
747 | === modified file 'src/eventview.cpp' |
748 | --- src/eventview.cpp 2015-10-01 19:44:45 +0000 |
749 | +++ src/eventview.cpp 2017-03-22 20:18:11 +0000 |
750 | @@ -1,5 +1,5 @@ |
751 | /* |
752 | - * Copyright (C) 2013 Canonical, Ltd. |
753 | + * Copyright (C) 2013-2017 Canonical, Ltd. |
754 | * |
755 | * Authors: |
756 | * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com> |
757 | @@ -128,6 +128,10 @@ |
758 | connect(Manager::instance(), |
759 | SIGNAL(eventsRemoved(History::Events)), |
760 | SLOT(_d_eventsRemoved(History::Events))); |
761 | + // we don't filter thread signals |
762 | + connect(Manager::instance(), |
763 | + SIGNAL(threadsRemoved(History::Threads)), |
764 | + SIGNAL(threadsRemoved(History::Threads))); |
765 | } |
766 | |
767 | EventView::~EventView() |
768 | |
769 | === modified file 'src/eventview.h' |
770 | --- src/eventview.h 2013-09-17 23:05:35 +0000 |
771 | +++ src/eventview.h 2017-03-22 20:18:11 +0000 |
772 | @@ -1,5 +1,5 @@ |
773 | /* |
774 | - * Copyright (C) 2013 Canonical, Ltd. |
775 | + * Copyright (C) 2013-2017 Canonical, Ltd. |
776 | * |
777 | * Authors: |
778 | * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com> |
779 | @@ -24,6 +24,7 @@ |
780 | |
781 | #include "types.h" |
782 | #include "event.h" |
783 | +#include "thread.h" |
784 | #include "filter.h" |
785 | #include "sort.h" |
786 | #include <QObject> |
787 | @@ -50,6 +51,7 @@ |
788 | void eventsAdded(const History::Events &events); |
789 | void eventsModified(const History::Events &events); |
790 | void eventsRemoved(const History::Events &events); |
791 | + void threadsRemoved(const History::Threads &threads); |
792 | void invalidated(); |
793 | |
794 | private: |
795 | |
796 | === modified file 'src/managerdbus.cpp' |
797 | --- src/managerdbus.cpp 2017-03-22 20:18:11 +0000 |
798 | +++ src/managerdbus.cpp 2017-03-22 20:18:11 +0000 |
799 | @@ -124,11 +124,8 @@ |
800 | return false; |
801 | } |
802 | |
803 | - QDBusReply<bool> reply = mInterface.call("RemoveThreads", QVariant::fromValue(threadMap)); |
804 | - if (!reply.isValid()) { |
805 | - return false; |
806 | - } |
807 | - return reply.value(); |
808 | + mInterface.asyncCall("RemoveThreads", QVariant::fromValue(threadMap)); |
809 | + return true; |
810 | } |
811 | |
812 | bool ManagerDBus::removeEvents(const Events &events) |
813 | @@ -138,11 +135,7 @@ |
814 | return false; |
815 | } |
816 | |
817 | - QDBusReply<bool> reply = mInterface.call("RemoveEvents", QVariant::fromValue(eventMap)); |
818 | - if (!reply.isValid()) { |
819 | - return false; |
820 | - } |
821 | - return reply.value(); |
822 | + mInterface.asyncCall("RemoveEvents", QVariant::fromValue(eventMap)); |
823 | } |
824 | |
825 | Thread ManagerDBus::getSingleThread(EventType type, const QString &accountId, const QString &threadId, const QVariantMap &properties) |
826 | |
827 | === modified file 'tests/Ubuntu.History/HistoryEventModelTest.cpp' |
828 | --- tests/Ubuntu.History/HistoryEventModelTest.cpp 2016-09-09 20:00:09 +0000 |
829 | +++ tests/Ubuntu.History/HistoryEventModelTest.cpp 2017-03-22 20:18:11 +0000 |
830 | @@ -1,5 +1,5 @@ |
831 | /* |
832 | - * Copyright (C) 2016 Canonical, Ltd. |
833 | + * Copyright (C) 2016-2017 Canonical, Ltd. |
834 | * |
835 | * This file is part of history-service. |
836 | * |
837 | |
838 | === modified file 'tests/libhistoryservice/ManagerTest.cpp' |
839 | --- tests/libhistoryservice/ManagerTest.cpp 2015-09-23 21:52:48 +0000 |
840 | +++ tests/libhistoryservice/ManagerTest.cpp 2017-03-22 20:18:11 +0000 |
841 | @@ -348,43 +348,11 @@ |
842 | History::Threads threads; |
843 | threads << textThread << voiceThread; |
844 | |
845 | - // insert some text and voice events |
846 | - History::Events events; |
847 | - for (int i = 0; i < 50; ++i) { |
848 | - History::TextEvent textEvent(textThread.accountId(), |
849 | - textThread.threadId(), |
850 | - QString("eventToBeRemoved%1").arg(i), |
851 | - textThread.participants().first().identifier(), |
852 | - QDateTime::currentDateTime(), |
853 | - true, |
854 | - QString("Hello world %1").arg(i), |
855 | - History::MessageTypeText); |
856 | - events.append(textEvent); |
857 | - |
858 | - History::VoiceEvent voiceEvent(voiceThread.accountId(), |
859 | - voiceThread.threadId(), |
860 | - QString("eventToBeRemoved%1").arg(i), |
861 | - voiceThread.participants().first().identifier(), |
862 | - QDateTime::currentDateTime(), |
863 | - true, |
864 | - true); |
865 | - events.append(voiceEvent); |
866 | - } |
867 | - |
868 | - QVERIFY(mManager->writeEvents(events)); |
869 | - |
870 | - QSignalSpy eventsRemovedSpy(mManager, SIGNAL(eventsRemoved(History::Events))); |
871 | QSignalSpy threadsRemovedSpy(mManager, SIGNAL(threadsRemoved(History::Threads))); |
872 | |
873 | QVERIFY(mManager->removeThreads(threads)); |
874 | - QTRY_COMPARE(eventsRemovedSpy.count(), 1); |
875 | QTRY_COMPARE(threadsRemovedSpy.count(), 1); |
876 | |
877 | - History::Events removedEvents = eventsRemovedSpy.first().first().value<History::Events>(); |
878 | - qSort(removedEvents); |
879 | - qSort(events); |
880 | - QCOMPARE(removedEvents, events); |
881 | - |
882 | History::Threads removedThreads = threadsRemovedSpy.first().first().value<History::Threads>(); |
883 | qSort(removedThreads); |
884 | qSort(threads); |
Code looks good, but would be good to remove the qDebug()'s as they are getting triggered on every eventsAdded, modified and so on.