From e2b19b832907325ea7580d3f3ad4679e473dbbea Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Wed, 14 Sep 2016 09:49:53 +0900 Subject: Room: change the way messages are ordered This replaces the one-by-one timestamp-ordering algorithm of adding new messages with copying the whole group of just-arrived messages to either the beginning or the end of the timeline. Since origin timestamps do not provide a reasonable order, findInsertionPos() is entirely deleted. processMessageEvent() is replaced by two functions: addNewMessageEvents() appends at messageEvents.end() while addHistoricalMessageEvents() inserts them at messageEvents.begin(). There's no official way to insert messages in the middle; cases when getPreviousContent() is called in parallel or a RoomMessagesJob runs on a gap somewhere in the middle of the timeline weren't considered before this commit and aren't considered in it. The new ordering requires you to understand where you have got your events from (or rather, where you want to insert them). In particular, updateData() that processes /sync results uses addNewMessageEvents(); getPreviousContent() calls addHistoricalMessageEvents(). In order to notify clients, a single newMessages() signal gives way to 3 new signals: 2 aboutToAdd*Messages() and a common addedMessages(). In addition, clients can derive from Room and use doAdd*Messages() virtual functions to alter/extend the behaviour. --- room.cpp | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) (limited to 'room.cpp') diff --git a/room.cpp b/room.cpp index 3683781b..64ff5a85 100644 --- a/room.cpp +++ b/room.cpp @@ -340,13 +340,14 @@ void Room::updateData(const SyncRoomData& data) processStateEvent(stateEvent); } - for( Event* timelineEvent: data.timeline ) + if (!data.timeline.empty()) { - - processMessageEvent(timelineEvent); - emit newMessage(timelineEvent); - // State changes can arrive in a timeline event - try to check those. - processStateEvent(timelineEvent); + for( Event* e: data.timeline ) + { + // State changes can arrive in a timeline event; so check those. + processStateEvent(e); + } + addNewMessageEvents(data.timeline); } for( Event* ephemeralEvent: data.ephemeral ) @@ -379,11 +380,7 @@ void Room::Private::getPreviousContent() connect( roomMessagesJob, &RoomMessagesJob::result, [=]() { if( !roomMessagesJob->error() ) { - for( Event* event: roomMessagesJob->events() ) - { - q->processMessageEvent(event); - emit q->newMessage(event); - } + q->addHistoricalMessageEvents(roomMessagesJob->events()); prevBatch = roomMessagesJob->end(); } roomMessagesJob = nullptr; @@ -396,9 +393,32 @@ Connection* Room::connection() const return d->connection; } -void Room::processMessageEvent(Event* event) +void Room::addNewMessageEvents(const Events& events) +{ + emit aboutToAddNewMessages(events); + doAddNewMessageEvents(events); + emit addedMessages(); +} + +void Room::doAddNewMessageEvents(const Events& events) +{ + d->messageEvents.reserve(d->messageEvents.size() + events.size()); + std::copy(events.begin(), events.end(), std::back_inserter(d->messageEvents)); +} + +void Room::addHistoricalMessageEvents(const Events& events) +{ + emit aboutToAddHistoricalMessages(events); + doAddHistoricalMessageEvents(events); + emit addedMessages(); +} + +void Room::doAddHistoricalMessageEvents(const Events& events) { - d->messageEvents.insert(findInsertionPos(d->messageEvents, event), event); + // Preserver the order of messages when inserting the block in the + // beginning of the container. + std::reverse_copy(events.begin(), events.end(), + std::front_inserter(d->messageEvents)); } void Room::processStateEvent(Event* event) -- cgit v1.2.3 From fab0bb1993b570e01333cfe4d8dc70e2a7bf87b7 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Wed, 14 Sep 2016 12:17:54 +0900 Subject: Group processing of state events as well --- room.cpp | 89 +++++++++++++++++++++++++++++----------------------------------- room.h | 2 +- 2 files changed, 41 insertions(+), 50 deletions(-) (limited to 'room.cpp') diff --git a/room.cpp b/room.cpp index 64ff5a85..b7c6450d 100644 --- a/room.cpp +++ b/room.cpp @@ -46,7 +46,7 @@ class Room::Private public: /** Map of user names to users. User names potentially duplicate, hence a multi-hashmap. */ typedef QMultiHash members_map_t; - + Private(Connection* c, const QString& id_) : q(nullptr), connection(c), id(id_), joinState(JoinState::Join) , roomMessagesJob(nullptr) @@ -76,7 +76,7 @@ class Room::Private QHash lastReadEvent; QString prevBatch; RoomMessagesJob* roomMessagesJob; - + // Convenience methods to work with the membersMap and usersLeft. // addMember() and removeMember() emit respective Room:: signals // after a succesful operation. @@ -335,18 +335,12 @@ void Room::updateData(const SyncRoomData& data) d->prevBatch = data.timelinePrevBatch; setJoinState(data.joinState); - for( Event* stateEvent: data.state ) - { - processStateEvent(stateEvent); - } + processStateEvents(data.state); if (!data.timeline.empty()) { - for( Event* e: data.timeline ) - { - // State changes can arrive in a timeline event; so check those. - processStateEvent(e); - } + // State changes can arrive in a timeline event; so check those. + processStateEvents(data.timeline); addNewMessageEvents(data.timeline); } @@ -421,56 +415,53 @@ void Room::doAddHistoricalMessageEvents(const Events& events) std::front_inserter(d->messageEvents)); } -void Room::processStateEvent(Event* event) +void Room::processStateEvents(const Events& events) { - if( event->type() == EventType::RoomName ) + for (auto event: events) { - if (RoomNameEvent* nameEvent = static_cast(event)) + if( event->type() == EventType::RoomName ) { + RoomNameEvent* nameEvent = static_cast(event); d->name = nameEvent->name(); qDebug() << "room name:" << d->name; d->updateDisplayname(); emit namesChanged(this); - } else + } + if( event->type() == EventType::RoomAliases ) { - qDebug() << - "!!! event type is RoomName but the event is not RoomNameEvent"; + RoomAliasesEvent* aliasesEvent = static_cast(event); + d->aliases = aliasesEvent->aliases(); + qDebug() << "room aliases:" << d->aliases; + // No displayname update - aliases are not used to render a displayname + emit namesChanged(this); } - } - if( event->type() == EventType::RoomAliases ) - { - RoomAliasesEvent* aliasesEvent = static_cast(event); - d->aliases = aliasesEvent->aliases(); - qDebug() << "room aliases:" << d->aliases; - // No displayname update - aliases are not used to render a displayname - emit namesChanged(this); - } - if( event->type() == EventType::RoomCanonicalAlias ) - { - RoomCanonicalAliasEvent* aliasEvent = static_cast(event); - d->canonicalAlias = aliasEvent->alias(); - qDebug() << "room canonical alias:" << d->canonicalAlias; - d->updateDisplayname(); - emit namesChanged(this); - } - if( event->type() == EventType::RoomTopic ) - { - RoomTopicEvent* topicEvent = static_cast(event); - d->topic = topicEvent->topic(); - emit topicChanged(); - } - if( event->type() == EventType::RoomMember ) - { - RoomMemberEvent* memberEvent = static_cast(event); - User* u = d->connection->user(memberEvent->userId()); - u->processEvent(event); - if( memberEvent->membership() == MembershipType::Join ) + if( event->type() == EventType::RoomCanonicalAlias ) + { + RoomCanonicalAliasEvent* aliasEvent = static_cast(event); + d->canonicalAlias = aliasEvent->alias(); + qDebug() << "room canonical alias:" << d->canonicalAlias; + d->updateDisplayname(); + emit namesChanged(this); + } + if( event->type() == EventType::RoomTopic ) { - d->addMember(u); + RoomTopicEvent* topicEvent = static_cast(event); + d->topic = topicEvent->topic(); + emit topicChanged(); } - else if( memberEvent->membership() == MembershipType::Leave ) + if( event->type() == EventType::RoomMember ) { - d->removeMember(u); + RoomMemberEvent* memberEvent = static_cast(event); + User* u = d->connection->user(memberEvent->userId()); + u->processEvent(event); + if( memberEvent->membership() == MembershipType::Join ) + { + d->addMember(u); + } + else if( memberEvent->membership() == MembershipType::Leave ) + { + d->removeMember(u); + } } } } diff --git a/room.h b/room.h index c64bed6f..1c29aa01 100644 --- a/room.h +++ b/room.h @@ -107,7 +107,7 @@ namespace QMatrixClient Connection* connection() const; virtual void doAddNewMessageEvents(const Events& events); virtual void doAddHistoricalMessageEvents(const Events& events); - virtual void processStateEvent(Event* event); + virtual void processStateEvents(const Events& events); virtual void processEphemeralEvent(Event* event); private: -- cgit v1.2.3 From b1ca4264f25db826a98455698f1e05babd85eb26 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Wed, 21 Sep 2016 07:29:25 +0900 Subject: Fixed the order of historical messages --- room.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'room.cpp') diff --git a/room.cpp b/room.cpp index b7c6450d..e08b45e8 100644 --- a/room.cpp +++ b/room.cpp @@ -409,10 +409,9 @@ void Room::addHistoricalMessageEvents(const Events& events) void Room::doAddHistoricalMessageEvents(const Events& events) { - // Preserver the order of messages when inserting the block in the - // beginning of the container. - std::reverse_copy(events.begin(), events.end(), - std::front_inserter(d->messageEvents)); + // Historical messages arrive in newest-to-oldest order + d->messageEvents.reserve(d->messageEvents.size() + events.size()); + std::copy(events.begin(), events.end(), std::front_inserter(d->messageEvents)); } void Room::processStateEvents(const Events& events) -- cgit v1.2.3