aboutsummaryrefslogtreecommitdiff
path: root/lib/room.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/room.cpp')
-rw-r--r--lib/room.cpp113
1 files changed, 66 insertions, 47 deletions
diff --git a/lib/room.cpp b/lib/room.cpp
index c6376a26..b0be288b 100644
--- a/lib/room.cpp
+++ b/lib/room.cpp
@@ -72,14 +72,6 @@ using std::llround;
enum EventsPlacement : int { Older = -1, Newer = 1 };
-// A workaround for MSVC 2015 and older GCC's that don't handle initializer
-// lists right (MSVC 2015, notably, fails with "error C2440: 'return':
-// cannot convert from 'initializer list' to 'QMatrixClient::FileTransferInfo'")
-#if (defined(_MSC_VER) && _MSC_VER < 1910) || \
- (defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 4)
-# define WORKAROUND_EXTENDED_INITIALIZER_LIST
-#endif
-
class Room::Private
{
public:
@@ -209,6 +201,28 @@ class Room::Private
is<RoomMessageEvent>(*ti);
}
+ template <typename EventArrayT>
+ Changes updateStateFrom(EventArrayT&& events)
+ {
+ Changes changes = NoChange;
+ if (!events.empty())
+ {
+ QElapsedTimer et; et.start();
+ for (auto&& eptr: events)
+ {
+ const auto& evt = *eptr;
+ Q_ASSERT(evt.isStateEvent());
+ // Update baseState afterwards to make sure that the old state
+ // is valid and usable inside processStateEvent
+ changes |= q->processStateEvent(evt);
+ baseState[{evt.matrixType(),evt.stateKey()}] = move(eptr);
+ }
+ if (events.size() > 9 || et.nsecsElapsed() >= profilerMinNsecs())
+ qCDebug(PROFILER) << "*** Room::Private::updateStateFrom():"
+ << events.size() << "event(s)," << et;
+ }
+ return changes;
+ }
Changes addNewMessageEvents(RoomEvents&& events);
void addHistoricalMessageEvents(RoomEvents&& events);
@@ -684,13 +698,7 @@ void Room::Private::getAllMembers()
auto nextIndex = timeline.empty() ? 0 : timeline.back().index() + 1;
connect( allMembersJob, &BaseJob::success, q, [=] {
Q_ASSERT(timeline.empty() || nextIndex <= q->maxTimelineIndex() + 1);
- Changes roomChanges = NoChange;
- for (auto&& e: allMembersJob->chunk())
- {
- const auto& evt = *e;
- baseState[{evt.matrixType(),evt.stateKey()}] = move(e);
- roomChanges |= q->processStateEvent(evt);
- }
+ auto roomChanges = updateStateFrom(allMembersJob->chunk());
// Replay member events that arrived after the point for which
// the full members list was requested.
if (!timeline.empty() )
@@ -1049,7 +1057,7 @@ FileTransferInfo Room::fileTransferInfo(const QString& id) const
total = INT_MAX;
}
-#ifdef WORKAROUND_EXTENDED_INITIALIZER_LIST
+#ifdef BROKEN_INITIALIZER_LISTS
FileTransferInfo fti;
fti.status = infoIt->status;
fti.progress = int(progress);
@@ -1296,21 +1304,8 @@ void Room::updateData(SyncRoomData&& data, bool fromCache)
for (auto&& event: data.accountData)
roomChanges |= processAccountDataEvent(move(event));
- if (!data.state.empty())
- {
- et.restart();
- for (auto&& eptr: data.state)
- {
- const auto& evt = *eptr;
- Q_ASSERT(evt.isStateEvent());
- d->baseState[{evt.matrixType(),evt.stateKey()}] = move(eptr);
- roomChanges |= processStateEvent(evt);
- }
+ roomChanges |= d->updateStateFrom(data.state);
- if (data.state.size() > 9 || et.nsecsElapsed() >= profilerMinNsecs())
- qCDebug(PROFILER) << "*** Room::processStateEvents():"
- << data.state.size() << "event(s)," << et;
- }
if (!data.timeline.empty())
{
et.restart();
@@ -1366,8 +1361,6 @@ RoomEvent* Room::Private::addAsPending(RoomEventPtr&& event)
event->setTransactionId(connection->generateTxnId());
auto* pEvent = rawPtr(event);
emit q->pendingEventAboutToAdd(pEvent);
- // FIXME: This sometimes causes a bad read:
- // https://travis-ci.org/QMatrixClient/libqmatrixclient/jobs/492156899#L2596
unsyncedEvents.emplace_back(move(event));
emit q->pendingEventAdded();
return pEvent;
@@ -1522,7 +1515,7 @@ QString Room::postPlainText(const QString& plainText)
}
QString Room::postHtmlMessage(const QString& plainText, const QString& html,
- MessageEventType type)
+ MessageEventType type)
{
return d->sendEvent<RoomMessageEvent>(plainText, type,
new EventContent::TextContent(html, QStringLiteral("text/html")));
@@ -1530,7 +1523,7 @@ QString Room::postHtmlMessage(const QString& plainText, const QString& html,
QString Room::postHtmlText(const QString& plainText, const QString& html)
{
- return postHtmlMessage(plainText, html, MessageEventType::Text);
+ return postHtmlMessage(plainText, html);
}
QString Room::postFile(const QString& plainText, const QUrl& localPath,
@@ -1614,6 +1607,11 @@ void Room::setCanonicalAlias(const QString& newAlias)
d->requestSetState(RoomCanonicalAliasEvent(newAlias));
}
+void Room::setAliases(const QStringList& aliases)
+{
+ d->requestSetState(RoomAliasesEvent(aliases));
+}
+
void Room::setTopic(const QString& newTopic)
{
d->requestSetState(RoomTopicEvent(newTopic));
@@ -1881,22 +1879,29 @@ RoomEventPtr makeRedacted(const RoomEvent& target,
const RedactionEvent& redaction)
{
auto originalJson = target.originalJsonObject();
- static const QStringList keepKeys =
- { EventIdKey, TypeKey, QStringLiteral("room_id"),
- QStringLiteral("sender"), QStringLiteral("state_key"),
- QStringLiteral("prev_content"), ContentKey,
- QStringLiteral("origin_server_ts") };
+ static const QStringList keepKeys {
+ EventIdKey, TypeKey, QStringLiteral("room_id"),
+ QStringLiteral("sender"), QStringLiteral("state_key"),
+ QStringLiteral("prev_content"), ContentKey,
+ QStringLiteral("hashes"), QStringLiteral("signatures"),
+ QStringLiteral("depth"), QStringLiteral("prev_events"),
+ QStringLiteral("prev_state"), QStringLiteral("auth_events"),
+ QStringLiteral("origin"), QStringLiteral("origin_server_ts"),
+ QStringLiteral("membership")
+ };
std::vector<std::pair<Event::Type, QStringList>> keepContentKeysMap
{ { RoomMemberEvent::typeId(), { QStringLiteral("membership") } }
- , { RoomCreateEvent::typeId(), { QStringLiteral("creator") } }
+ , { RoomCreateEvent::typeId(), { QStringLiteral("creator") } }
// , { RoomJoinRules::typeId(), { QStringLiteral("join_rule") } }
// , { RoomPowerLevels::typeId(),
// { QStringLiteral("ban"), QStringLiteral("events"),
// QStringLiteral("events_default"), QStringLiteral("kick"),
// QStringLiteral("redact"), QStringLiteral("state_default"),
// QStringLiteral("users"), QStringLiteral("users_default") } }
- , { RoomAliasesEvent::typeId(), { QStringLiteral("alias") } }
+ , { RoomAliasesEvent::typeId(), { QStringLiteral("aliases") } }
+// , { RoomHistoryVisibility::typeId(),
+// { QStringLiteral("history_visibility") } }
};
for (auto it = originalJson.begin(); it != originalJson.end();)
{
@@ -2050,15 +2055,21 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events)
it = nextPending + 1;
auto* nextPendingEvt = nextPending->get();
- emit q->pendingEventAboutToMerge(nextPendingEvt,
- int(nextPendingPair.second - unsyncedEvents.begin()));
+ const auto pendingEvtIdx =
+ int(nextPendingPair.second - unsyncedEvents.begin());
+ emit q->pendingEventAboutToMerge(nextPendingEvt, pendingEvtIdx);
qDebug(EVENTS) << "Merging pending event from transaction"
<< nextPendingEvt->transactionId() << "into"
<< nextPendingEvt->id();
auto transfer = fileTransfers.take(nextPendingEvt->transactionId());
if (transfer.status != FileTransferInfo::None)
fileTransfers.insert(nextPendingEvt->id(), transfer);
- unsyncedEvents.erase(nextPendingPair.second);
+ // After emitting pendingEventAboutToMerge() above we cannot rely
+ // on the previously obtained nextPendingPair.second staying valid
+ // because a signal handler may send another message, thereby altering
+ // unsyncedEvents (see #286). Fortunately, unsyncedEvents only grows at
+ // its back so we can rely on the index staying valid at least.
+ unsyncedEvents.erase(unsyncedEvents.begin() + pendingEvtIdx);
if (auto insertedSize = moveEventsToTimeline({nextPending, it}, Newer))
{
totalInserted += insertedSize;
@@ -2148,8 +2159,12 @@ Room::Changes Room::processStateEvent(const RoomEvent& e)
if (!e.isStateEvent())
return Change::NoChange;
- d->currentState[{e.matrixType(),e.stateKey()}] =
- static_cast<const StateEventBase*>(&e);
+ const auto* oldStateEvent = std::exchange(
+ d->currentState[{e.matrixType(),e.stateKey()}],
+ static_cast<const StateEventBase*>(&e));
+ Q_ASSERT(!oldStateEvent ||
+ (oldStateEvent->matrixType() == e.matrixType() &&
+ oldStateEvent->stateKey() == e.stateKey()));
if (!is<RoomMemberEvent>(e))
qCDebug(EVENTS) << "Room state event:" << e;
@@ -2157,7 +2172,11 @@ Room::Changes Room::processStateEvent(const RoomEvent& e)
, [] (const RoomNameEvent&) {
return NameChange;
}
- , [] (const RoomAliasesEvent&) {
+ , [this,oldStateEvent] (const RoomAliasesEvent& ae) {
+ const auto previousAliases = oldStateEvent
+ ? static_cast<const RoomAliasesEvent*>(oldStateEvent)->aliases()
+ : QStringList();
+ connection()->updateRoomAliases(id(), previousAliases, ae.aliases());
return OtherChange;
}
, [this] (const RoomCanonicalAliasEvent& evt) {