aboutsummaryrefslogtreecommitdiff
path: root/lib
AgeCommit message (Collapse)Author
2022-09-12Fix a leak in Connection::saveAccessTokenToKeychain()Alexey Rusakov
2022-09-10Adjust converters.h logic to support Qt 6.4Alexey Rusakov
There's a bit convoluted stack of calls involved here, worth laying out. C++ containers are loaded from JSON containers by calling fromJson<> on each element of the JSON container, specialised by the element type of the C++ container. If that element type is not itself an object (e.g., QString), the respective specialisation of fromJson<> is supposed to kick-in and override the default template that delegates the conversion to JsonConverter (which in turn falls back to JsonObjectConverter unless specialised for that type). Because template functions cannot be partially specialised, that specialised overload for, say, QString, is not complete: it accepts QJsonValue but anything except QJsonValue will hit the generic overload instead. That makes the whole fromJson<> machinery quite sensitive to the exact JSON type passed to it; but as of Qt 5, the types actually presented to fromJson() were limited to QJsonValue and QJsonDocument (okay, QJsonObject and QJsonArray could also be there but the QJsonObject case is trivial for JsonConverter and containers loaded from QJsonArray are all caught with JsonArrayConverter). Qt 6 started returning (const) QJsonValueRef from `QJson*::const_iterator::operator*()` - meaning that whenever a simple type (like, again, QString) is loaded within the bigger container, the "wrong" fromJson() gets called. To fix this, JsonObjectUnpacker gained a dedicated function to unpack QJsonValueRef. QJsonValueRef is an old name existing since Qt 5.15 - no big pain. However, in Qt 6.4 QJsonValueConstRef is getting introduced for the same purpose. It's possible to wrap the *Ref overloads in some #if/#else brackets but at that point it becomes easier to just produce QJsonValue from whatever QJson* iterators dereference to.
2022-09-09makeImpl: add support for aggregate initialisationAlexey Rusakov
Since C++17, parentheses only work when a constructor is there, while braces allow both calling a constructor and aggregate initialisation.
2022-09-05CleanupAlexey Rusakov
2022-09-05sendToDevice: fix unintended slicingAlexey Rusakov
Ironically, this slicing would not break anything as all the necessary data are saved in the Event parent class; but the code is very fragile and scary.
2022-09-04SingleKeyValue: use reference for template parameterAlexey Rusakov
I guess it was simply overlooked originally; in any case, currently used compilers deal with the reference just as fine as with the pointer.
2022-09-04Room::setTags(): skip full-blown TagEvent creationAlexey Rusakov
TagEvent is only created to immediately extract content JSON from it; at the same rate content JSON can be generated directly from content.
2022-09-04StateEventBase -> StateEventAlexey Rusakov
Now that StateEvent name is vacated, the naming for event core classes can be completely unified: Event, RoomEvent, CallEvent, StateEvent.
2022-09-04concept EventClassAlexey Rusakov
Constrain types to derive from Event (or the chosen class), where applicable.
2022-09-04Disallow direct events construction from JSONAlexey Rusakov
Direct construction (using makeEvent() or explicitly constructing an event) from JSON may create an event that has a type conflicting with that stored in JSON. There's no such problem with loadEvent(), even though it's considerably slower. Driven by the fact that almost nowhere in the code direct construction is used on checked JSON (one test is the only valid case), this commit moves all JSON-loading constructors to the protected section, thereby disabling usage of makeEvent() in JSON-loading capacity, and switches such cases across the library to loadEvent().
2022-09-04CallEventBase -> CallEvent; pack up all call eventsAlexey Rusakov
These are small enough to comfortably reside in a single translation unit.
2022-09-04RoomStateView::content()Alexey Rusakov
This gives a more conventional API compared to queryOr() that can be used for event objects that have content() defined - with the downside being that content() unpacks the entire object instead of retrieving one particular piece (but for state events and single key-value content it's not a problem, and those make for the vast majority of events).
2022-09-04More cleanupAlexey Rusakov
2022-09-04Remove #include "logging.h" from event.hAlexey Rusakov
We don't expose logging internals to the outside world.
2022-09-04Regenerate CS API upon GTAD config changeAlexey Rusakov
2022-09-04Streamline event typesAlexey Rusakov
This commit introduces a few things to further reduce the boilerplate across event type definitions: - Event type is no more separately stored in Event and therefore no more passed to base event constructors. Until the previous commit, it was used by is() to quickly match the event type; with the new event metatype class, the same is achieved even quicker by comparing metatype pointers. - EventTemplate is a generalisation of StateEvent for all event types providing common constructor signatures and content() for (most) leaf event types. StateEvent therefore has become a partial specialisation of EventTemplate for types derived from StateEventBase; as the known client code base does not use it directly, a compatibility alias is not provided. Also, DEFINE_SIMPLE_EVENT now expands into a class deriving from EventTemplate. - On top of StateEvent->EventTemplate specialisation, KeyedStateEventBase and KeylessStateEventBase types are introduced with appropriate constructor signatures (with or without state_key, respectively) to allow `using` of them from derived event types. To facilitate writing of constraints, concepts for keyed and keyless state event types are also introduced; RoomStateView, e.g., makes use of those to provide appropriate method signatures. - typeId(), unknownEventTypeId(), UnknownEventTypeId are no more provided - they weren't used throughout the known code base (Quaternion, NeoChat), and the concept of "unknown event types" is hereby eliminated entirely. - RoomKeyEvent no more accepts senderId as a parameter; it has never been a good practice as the sender is assigned by Connection anyway.
2022-09-04EventMetaType, QUO_EVENT, QUO_BASE_EVENTAlexey Rusakov
The new metatype framework replaces EventFactory/DEFINE_EVENT_TYPEID/REGISTER_EVENT_TYPE; it is faster, more functional and extensible. Of note: - EventMetaType mostly reproduces the logic of EventFactory but supports custom base event types not just for loading (that part EventFactory also supported) but also for matching - previously you had to have Event::is*Event() for base type matching. Now Quotient::is() can match against both base and leaf types. - Instead of DEFINE_EVENT_TYPEID and REGISTER_EVENT_TYPE there's now a single macro, QUO_EVENT, intended for use in the way similar to Q_OBJECT. Actually, the entire framework borrows heavily from QMetaObject and Q_OBJECT. Making event types full-fledged QObjects is still not considered because half of QObject functions would not be applicable (e.g. signals/slots) while another half (in particular, using Matrix type ids to select event types) would still have to be done on top of QObject. And QML can just access events as const QJsonObjects which is arguably more lightweight as well. - QUO_BASE_EVENT is a new macro replacing EventFactory object definitions. This was necessary for the same reason why Q_OBJECT is a macro: aside from a static object definition, this macro introduces a virtual function override to resolve the metatype at runtime. This very mechanism is used to make event type matching/casting as quick as possible - QUO_BASE_EVENT and QUO_EVENT use the C++20 __VA_OPT__ feature that is only available with the new MSVC preprocessor (see https://docs.microsoft.com/en-us/cpp/preprocessor/preprocessor-experimental-overview); the respective switch was added to CMakeLists.txt.
2022-09-04DEFINE_SIMPLE_EVENT: support custom JSON keysAlexey Rusakov
2022-09-04SingleKeyValue: allow seamless construction from the underlying typeAlexey Rusakov
SingleKeyValue is a tiny wrapper and supposed to be discreet. Having to explicitly (even if only with braces) construct its objects stands in the way of readability on the consuming side of the code and sometimes prevents direct initialisation of event objects without constructors getting some kind of ContentParamTs parameter pack where a single content_type argument would suffice otherwise.
2022-09-04Fix a typo in cacheLocation() doc-commentAlexey Rusakov
[skip ci]
2022-09-03KeyVerificationDoneEvent: fix copy-pasta in DEFINE_EVENT_TYPEIDAlexey Rusakov
2022-08-26Fix device verificationTobias Fella
QByteArrays don't like interacting with QStrings
2022-08-26Merge #547: Implement device verificationAlexey Rusakov
2022-08-25CleanupAlexey Rusakov
2022-08-25Refactor the code handling emojiAlexey Rusakov
- Use a dedicated structure, EmojiEntry, instead of QVariantMap (it's Q_GADGET, should be readable from QML just fine) - While we're at it, QVector is better than QList in Qt 5.15 - Remove language from the session state - it's used in a single method - Modernise handleKey() code
2022-08-25More code reorganisationAlexey Rusakov
- Common switchOnType() piece for key verification events is factored out into processIfVerificationEvent() - Bare event JSON removed from KeyVerificationSession into constructors of respective events - Connection::sendToDevice() uses assembleEncryptedContent() introduced in the previous commit - commonSupportedMethods() moved out to .cpp; error/string converters made static
2022-08-25Connection::Private::assembleEncryptedContent()Alexey Rusakov
What was partially factored out before into encryptSessionKeyEvent() is now the complete algorithm converting any event json into encrypted content.
2022-08-25KeyVerificationSession: cleanupAlexey Rusakov
- Use std::chrono for the timeout (it's more readable and less ambiguous) and make it a local variable - Only pass a Connection object once to constructors - Ensure buildability even without E2EE (key verification is disabled in that case) - Reorder #includes - Other cleanup following clang-tidy warnings
2022-08-24Merge branch 'dev' into device-verificationAlexey Rusakov
# Conflicts: # autotests/testfilecrypto.cpp # lib/connection.cpp # lib/connection.h # lib/database.cpp # lib/database.h # lib/e2ee/qolmoutboundsession.cpp # lib/e2ee/qolmoutboundsession.h # lib/eventitem.h # lib/events/encryptedevent.cpp # lib/events/encryptedevent.h # lib/events/encryptedfile.cpp # lib/events/encryptedfile.h # lib/events/keyverificationevent.cpp # lib/events/keyverificationevent.h # lib/events/roomkeyevent.h # lib/room.cpp # lib/room.h
2022-08-10Emit Room::newFileTransfer when downloading a fileTobias Fella
2022-08-05eventloader.h: use basicJson() in a uniform wayAlexey Rusakov
There's no particular reason the order of parameters in StateEventBase::basicJson() should be as it was, and (the only) loadStateEvent() usage in room.cpp suggests the unified order is more convenient. Besides, this order is aligned with that in the StateEventBase constructor.
2022-08-05Fix Connection::accountData<>()Alexey Rusakov
The template version has never worked, to the point where instantiating it would immediately lead to FTBFS. The new version returns an event pointer as a simpler fix that would make it usable - in particular, there's no more need to have separate Connection::Private::unpackAccountData(). To simplify the fix, eventCast() has been made more tolerating - passing nullptr to it is processed in an expected (no-op) way now.
2022-08-01EventItem: use doc-comments correctlyAlexey Rusakov
[skip ci]
2022-08-01Fix FTBFSAlexey Rusakov
2022-08-01Pull out common JsonConverter code to JsonObjectUnpackerAlexey Rusakov
2022-07-30moving eventCast(): disallow passing nullptrAlexey Rusakov
This is aligned with the non-moving version.
2022-07-29Moving eventCast()Alexey Rusakov
In a situation where you have an EventPtr that you want to place somewhere as an `event_ptr_tt<SomeMoreSpecificEventType>` you have to carefully check that the stored event is actually of SomeMoreSpecificType and if it is, release() that event pointer, downcast, and re-wrap it into that new event_ptr_tt - or, as can be seen from the diff here, re-loadEvent() from JSON, which is simpler but inefficient. To help clients, and the library, eventCast() can now accept an rvalue smart pointer and do all the necessary things with it.
2022-07-26...and the definitive fixAlexey Rusakov
2022-07-26Another fix attemptAlexey Rusakov
2022-07-26Hopefully fix building with GCCAlexey Rusakov
The last commit broke it.
2022-07-26Add missing QUOTIENT_API piecesAlexey Rusakov
The upcoming event type infrastructure finally helps to detect those omissions more or less reliably (for event types only though).
2022-07-25Fix accidentally logging all receipt authorsAlexey Rusakov
...instead of just the number of them.
2022-07-25Don't redact certain event types even though lib doesn't know themAlexey Rusakov
Event type ids don't need a C++ type to be used, and clients might define those types on their side (NeoChat does that, e.g.).
2022-07-16Speed up read receipt updatesAlexey Rusakov
Profiling revealed 3 inefficiencies in read receipts code - and given there are a lot of them coming, these inefficiences quickly add up. Fixing them allows to slash read receipt processing time by 60%, and the total time of updating a room by more than a half. 1. Room::lastReadEventChanged() is emitted per receipt. This can be taxing on initial syncs or in bigger rooms; this commit converts it to an aggregate signal only emitted once per sync room batch and carrying the list of all user ids (more on that below) with updated read receipts. For that, Room::P::setLastReadEvent() is split into Room::P::setLocalLastReadEvent() that is called whenever the local read receipt has to be updated, and setLastReadEvent() proper that is very fast and only updates the internal data structures, nothing else. setLocalLastEvent() calls it, as does processEphemeralEvents(); both take responsibility to emit lastReadEventChanged() depending on the outcome of setLastReadEvent() invocation(s). 2. Massively aggravating the above point, user id from each read receipt is turned to a User object - and since most of the users are unknown at early moments, this causes thousands of allocations. Therefore the new aggregated lastReadEventChanged() only carries user ids, and clients will have to resolve them to User objects if they need. 3. Despite fairly tight conditions (note we're talking about thousands of receipts), Quotient still creates an intermediate C++ structure (EventsWithReceipts), only for the sake of passing it to processEphemeralEvent() that immediately disassembles it back again, converting to a series of calls to set(Local)LastReadEvent(). To fix this, processEphemeralEvent() now takes the event content JSON directly and iterates over it instead. Aside from that, a few extraneous conditions and logging has been removed and the whole function rewritten with switchOnType() to reduce cognitive complexity.
2022-07-16Room::decryptIncomingEvents()Alexey Rusakov
The result of factoring out duplicate code.
2022-07-16logging.h: suppress clang-tidy warningsAlexey Rusakov
2022-07-15Connection::user(): validate after lookup, not beforeAlexey Rusakov
If userMap only holds valid ids, there's no reason to spend time validating the sought id: if it's invalid, it won't be found. And lookups over a hash map are cheap.
2022-07-15operator<<(QDebug, QElapsedTimer): always use msAlexey Rusakov
That switch between micro- and milliseconds was pure visual sugaring, in a potentially time-sensitive context. Also: there's no sense in using const-ref for a small parameter in a function that is, to top it off, almost always inlined.
2022-07-13eventcontent.h: Use C++17 nested namespaces notationAlexey Rusakov
2022-07-12converters.*: facilities to convert enumsAlexey Rusakov
This introduces enumTo/FromJsonString() and flagTo/FromJsonString(), four facility functions to simplify conversion between C++ enums and JSON, and refactors a couple of places where it's useful.