From 6ea1fb621488910de055bd3af4d00343a763541a Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Mon, 5 Mar 2018 10:16:20 +0900 Subject: ReadMarkerEvent; TagEvent remade with less boilerplate code tagevent.h -> accountdataevents.h now has a macro to define more simplistic events along the lines of simplestateevents.h but inheriting from Event instead. TagEvent and ReadMarkerEvent(m.fully_read) are defined using this macro. ReadMarkerEvent is also wired through event.* (but not further yet). --- libqmatrixclient.pri | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'libqmatrixclient.pri') diff --git a/libqmatrixclient.pri b/libqmatrixclient.pri index 7cfa94a1..c7b95617 100644 --- a/libqmatrixclient.pri +++ b/libqmatrixclient.pri @@ -24,7 +24,7 @@ HEADERS += \ $$PWD/events/roomavatarevent.h \ $$PWD/events/typingevent.h \ $$PWD/events/receiptevent.h \ - $$PWD/events/tagevent.h \ + $$PWD/events/accountdataevents.h \ $$PWD/events/redactionevent.h \ $$PWD/jobs/requestdata.h \ $$PWD/jobs/basejob.h \ @@ -56,7 +56,6 @@ SOURCES += \ $$PWD/events/roommemberevent.cpp \ $$PWD/events/typingevent.cpp \ $$PWD/events/receiptevent.cpp \ - $$PWD/events/tagevent.cpp \ $$PWD/jobs/requestdata.cpp \ $$PWD/jobs/basejob.cpp \ $$PWD/jobs/checkauthmethods.cpp \ -- cgit v1.2.3 From 63efbe26f37819048bb236d4839cc5f25c102785 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Mon, 5 Mar 2018 21:06:16 +0900 Subject: Support server-side read marker (m.full_read) Closes #183. There's also the m.read part but it can be done sometime later, as it's pure optimisation. --- events/receiptevent.cpp | 6 ---- events/receiptevent.h | 2 -- jobs/postreadmarkersjob.h | 37 ++++++++++++++++++++ libqmatrixclient.pri | 3 +- room.cpp | 87 +++++++++++++++++++++++++---------------------- 5 files changed, 86 insertions(+), 49 deletions(-) create mode 100644 jobs/postreadmarkersjob.h (limited to 'libqmatrixclient.pri') diff --git a/events/receiptevent.cpp b/events/receiptevent.cpp index 3c4d34ee..7555db82 100644 --- a/events/receiptevent.cpp +++ b/events/receiptevent.cpp @@ -66,11 +66,5 @@ ReceiptEvent::ReceiptEvent(const QJsonObject& obj) } _eventsWithReceipts.push_back({eventIt.key(), std::move(receipts)}); } - static const auto UnreadMsgsKey = - QStringLiteral("x-qmatrixclient.unread_messages"); - if (contents.contains(UnreadMsgsKey)) - _unreadMessages = contents["x-qmatrixclient.unread_messages"].toBool(); - else - _unreadMessages = obj["x-qmatrixclient.unread_messages"].toBool(); } diff --git a/events/receiptevent.h b/events/receiptevent.h index 92dace82..5b99ae3f 100644 --- a/events/receiptevent.h +++ b/events/receiptevent.h @@ -41,12 +41,10 @@ namespace QMatrixClient EventsWithReceipts eventsWithReceipts() const { return _eventsWithReceipts; } - bool unreadMessages() const { return _unreadMessages; } static constexpr const char* const TypeId = "m.receipt"; private: EventsWithReceipts _eventsWithReceipts; - bool _unreadMessages; // Spec extension for caching purposes }; } // namespace QMatrixClient diff --git a/jobs/postreadmarkersjob.h b/jobs/postreadmarkersjob.h new file mode 100644 index 00000000..d0198821 --- /dev/null +++ b/jobs/postreadmarkersjob.h @@ -0,0 +1,37 @@ +/****************************************************************************** + * Copyright (C) 2017 Kitsune Ral + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "basejob.h" + +using namespace QMatrixClient; + +class PostReadMarkersJob : public BaseJob +{ + public: + explicit PostReadMarkersJob(const QString& roomId, + const QString& readUpToEventId) + : BaseJob(HttpVerb::Post, "PostReadMarkersJob", + QStringLiteral("_matrix/client/r0/rooms/%1/read_markers") + .arg(roomId)) + { + setRequestData(QJsonObject {{ + QStringLiteral("m.fully_read"), readUpToEventId }}); + } +}; diff --git a/libqmatrixclient.pri b/libqmatrixclient.pri index c7b95617..74e9d8c7 100644 --- a/libqmatrixclient.pri +++ b/libqmatrixclient.pri @@ -42,7 +42,8 @@ HEADERS += \ $$PWD/settings.h \ $$PWD/networksettings.h \ $$PWD/networkaccessmanager.h \ - $$PWD/jobs/downloadfilejob.h + $$PWD/jobs/downloadfilejob.h \ + $$PWD/jobs/postreadmarkersjob.h SOURCES += \ $$PWD/connectiondata.cpp \ diff --git a/room.cpp b/room.cpp index 4f818473..beeca6e3 100644 --- a/room.cpp +++ b/room.cpp @@ -36,6 +36,7 @@ #include "jobs/roommessagesjob.h" #include "jobs/mediathumbnailjob.h" #include "jobs/downloadfilejob.h" +#include "jobs/postreadmarkersjob.h" #include "avatar.h" #include "connection.h" #include "user.h" @@ -105,6 +106,7 @@ class Room::Private QString firstDisplayedEventId; QString lastDisplayedEventId; QHash lastReadEventIds; + QString serverReadMarker; TagsMap tags; QHash accountData; QString prevBatch; @@ -202,11 +204,12 @@ class Room::Private */ void processRedaction(RoomEventPtr redactionEvent); - template - SetAccountDataPerRoomJob* setAccountData(const EvT& event) + void broadcastTagUpdates() { - return connection->callApi( - connection->userId(), id, EvT::typeId(), event.toJson()); + connection->callApi( + connection->userId(), id, TagEvent::typeId(), + TagEvent(tags).toJson()); + emit q->tagsChanged(); } QJsonObject toJson() const; @@ -347,7 +350,11 @@ void Room::Private::setLastReadEvent(User* u, const QString& eventId) storedId = eventId; emit q->lastReadEventChanged(u); if (isLocalUser(u)) + { + if (eventId != serverReadMarker) + connection->callApi(id, eventId); emit q->readMarkerMoved(); + } } Room::Private::rev_iter_pair_t @@ -402,9 +409,8 @@ void Room::Private::markMessagesAsRead(Room::rev_iter_t upToMarker) { if ((*markers.second)->senderId() != q->localUser()->id()) { - auto eventId = (*markers.second)->id(); - connection->callApi(id, "m.read", eventId); - setAccountData(ReadMarkerEvent(eventId)); + connection->callApi(id, "m.read", + (*markers.second)->id()); break; } } @@ -593,8 +599,7 @@ void Room::addTag(const QString& name, const TagRecord& record) return; d->tags.insert(name, record); - d->setAccountData(TagEvent(d->tags)); - emit tagsChanged(); + d->broadcastTagUpdates(); } void Room::removeTag(const QString& name) @@ -603,8 +608,7 @@ void Room::removeTag(const QString& name) return; d->tags.remove(name); - d->setAccountData(TagEvent(d->tags)); - emit tagsChanged(); + d->broadcastTagUpdates(); } void Room::setTags(const TagsMap& newTags) @@ -612,8 +616,7 @@ void Room::setTags(const TagsMap& newTags) if (newTags == d->tags) return; d->tags = newTags; - d->setAccountData(TagEvent(d->tags)); - emit tagsChanged(); + d->broadcastTagUpdates(); } bool Room::isFavourite() const @@ -915,10 +918,13 @@ void Room::updateData(SyncRoomData&& data) d->prevBatch = data.timelinePrevBatch; setJoinState(data.joinState); - QElapsedTimer et; + QElapsedTimer et; et.start(); + for (auto&& event: data.accountData) + processAccountDataEvent(move(event)); + if (!data.state.empty()) { - et.start(); + et.restart(); processStateEvents(data.state); qCDebug(PROFILER) << "*** Room::processStateEvents(state):" << data.state.size() << "event(s)," << et; @@ -938,9 +944,6 @@ void Room::updateData(SyncRoomData&& data) for( auto&& ephemeralEvent: data.ephemeral ) processEphemeralEvent(move(ephemeralEvent)); - for (auto&& event: data.accountData) - processAccountDataEvent(move(event)); - if( data.highlightCount != d->highlightCount ) { d->highlightCount = data.highlightCount; @@ -1499,8 +1502,6 @@ void Room::processEphemeralEvent(EventPtr event) qCDebug(PROFILER) << "*** Room::processEphemeralEvent(receipts):" << receiptEvent->eventsWithReceipts().size() << "events with receipts," << et; - if (receiptEvent->unreadMessages()) - d->unreadMessages = true; break; } default: @@ -1524,6 +1525,20 @@ void Room::processAccountDataEvent(EventPtr event) emit tagsChanged(); break; } + case EventType::ReadMarker: + { + const auto* rmEvent = static_cast(event.get()); + const auto& readEventId = rmEvent->event_id(); + qCDebug(MAIN) << "Server-side read marker at " << readEventId; + static const auto UnreadMsgsKey = + QStringLiteral("x-qmatrixclient.unread_messages"); + if (rmEvent->contentJson().contains(UnreadMsgsKey)) + d->unreadMessages = + rmEvent->contentJson().value(UnreadMsgsKey).toBool(); + d->serverReadMarker = readEventId; + markMessagesAsRead(readEventId); + break; + } default: d->accountData[event->jsonType()] = event->contentJson().toVariantHash(); @@ -1659,32 +1674,24 @@ QJsonObject Room::Private::toJson() const QJsonObject {{ QStringLiteral("events"), stateEvents }}); } - if (!q->readMarkerEventId().isEmpty()) - { - result.insert(QStringLiteral("ephemeral"), - QJsonObject {{ QStringLiteral("events"), - QJsonArray { QJsonObject( - { { QStringLiteral("type"), QStringLiteral("m.receipt") } - , { QStringLiteral("content"), QJsonObject( - { { q->readMarkerEventId(), - QJsonObject {{ QStringLiteral("m.read"), - QJsonObject {{ connection->userId(), {} }} }} - } - , { QStringLiteral("x-qmatrixclient.unread_messages"), - unreadMessages } - }) } - } - ) } - }}); - } - QJsonArray accountDataEvents; if (!tags.empty()) accountDataEvents.append(QJsonObject( - { { QStringLiteral("type"), QStringLiteral("m.tag") } + { { QStringLiteral("type"), TagEvent::typeId() } , { QStringLiteral("content"), TagEvent(tags).toJson() } })); + if (!serverReadMarker.isEmpty()) + { + auto contentJson = ReadMarkerEvent(serverReadMarker).toJson(); + contentJson.insert(QStringLiteral("x-qmatrixclient.unread_messages"), + unreadMessages); + accountDataEvents.append(QJsonObject( + { { QStringLiteral("type"), ReadMarkerEvent::typeId() } + , { QStringLiteral("content"), contentJson } + })); + } + if (!accountData.empty()) { for (auto it = accountData.begin(); it != accountData.end(); ++it) -- cgit v1.2.3 From 962f7f4beb192810afe82bfd4b68613a96a69063 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Tue, 27 Feb 2018 11:41:09 +0900 Subject: Introduce DirectChatEvent (parse only, no processing yet) --- CMakeLists.txt | 1 + events/directchatevent.cpp | 36 ++++++++++++++++++++++++++++++++++++ events/directchatevent.h | 34 ++++++++++++++++++++++++++++++++++ events/event.cpp | 3 ++- libqmatrixclient.pri | 2 ++ 5 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 events/directchatevent.cpp create mode 100644 events/directchatevent.h (limited to 'libqmatrixclient.pri') diff --git a/CMakeLists.txt b/CMakeLists.txt index e95c72d0..82ab2b55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,6 +60,7 @@ set(libqmatrixclient_SRCS events/roomavatarevent.cpp events/typingevent.cpp events/receiptevent.cpp + events/directchatevent.cpp jobs/requestdata.cpp jobs/basejob.cpp jobs/checkauthmethods.cpp diff --git a/events/directchatevent.cpp b/events/directchatevent.cpp new file mode 100644 index 00000000..7049d967 --- /dev/null +++ b/events/directchatevent.cpp @@ -0,0 +1,36 @@ +/****************************************************************************** + * Copyright (C) 2018 Kitsune Ral + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "directchatevent.h" + +#include "converters.h" + +using namespace QMatrixClient; + +DirectChatEvent::DirectChatEvent(const QJsonObject& obj) + : Event(Type::DirectChat, obj) +{ } + +QMultiHash DirectChatEvent::usersToDirectChats() const +{ + QMultiHash result; + for (auto it = contentJson().begin(); it != contentJson().end(); ++it) + for (auto roomIdValue: it.value().toArray()) + result.insert(it.key(), roomIdValue.toString()); + return result; +} diff --git a/events/directchatevent.h b/events/directchatevent.h new file mode 100644 index 00000000..2b0ad0a0 --- /dev/null +++ b/events/directchatevent.h @@ -0,0 +1,34 @@ +/****************************************************************************** + * Copyright (C) 2018 Kitsune Ral + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "event.h" + +namespace QMatrixClient +{ + class DirectChatEvent : public Event + { + public: + explicit DirectChatEvent(const QJsonObject& obj); + + QMultiHash usersToDirectChats() const; + + static constexpr const char * TypeId = "m.direct"; + }; +} diff --git a/events/event.cpp b/events/event.cpp index f3e965e2..8ddf3945 100644 --- a/events/event.cpp +++ b/events/event.cpp @@ -25,6 +25,7 @@ #include "typingevent.h" #include "receiptevent.h" #include "accountdataevents.h" +#include "directchatevent.h" #include "redactionevent.h" #include "logging.h" @@ -88,7 +89,7 @@ EventPtr _impl::doMakeEvent(const QJsonObject& obj) return EventPtr(move(e)); return EventPtr { makeIfMatches( + TypingEvent, ReceiptEvent, TagEvent, ReadMarkerEvent, DirectChatEvent>( obj, obj["type"].toString()) }; } diff --git a/libqmatrixclient.pri b/libqmatrixclient.pri index 74e9d8c7..144c9dbc 100644 --- a/libqmatrixclient.pri +++ b/libqmatrixclient.pri @@ -25,6 +25,7 @@ HEADERS += \ $$PWD/events/typingevent.h \ $$PWD/events/receiptevent.h \ $$PWD/events/accountdataevents.h \ + $$PWD/events/directchatevent.h \ $$PWD/events/redactionevent.h \ $$PWD/jobs/requestdata.h \ $$PWD/jobs/basejob.h \ @@ -57,6 +58,7 @@ SOURCES += \ $$PWD/events/roommemberevent.cpp \ $$PWD/events/typingevent.cpp \ $$PWD/events/receiptevent.cpp \ + $$PWD/events/directchatevent.cpp \ $$PWD/jobs/requestdata.cpp \ $$PWD/jobs/basejob.cpp \ $$PWD/jobs/checkauthmethods.cpp \ -- cgit v1.2.3