diff options
-rw-r--r-- | .github/workflows/ci.yml | 66 | ||||
-rw-r--r-- | .github/workflows/sonar.yml | 113 | ||||
-rw-r--r-- | CMakeLists.txt | 7 | ||||
-rw-r--r-- | lib/events/callcandidatesevent.cpp | 27 | ||||
-rw-r--r-- | lib/events/callhangupevent.cpp | 36 | ||||
-rw-r--r-- | lib/events/callhangupevent.h | 8 | ||||
-rw-r--r-- | lib/events/event.h | 166 | ||||
-rw-r--r-- | lib/events/eventloader.h | 18 | ||||
-rw-r--r-- | lib/events/roomevent.cpp | 3 | ||||
-rw-r--r-- | lib/events/roomevent.h | 2 | ||||
-rw-r--r-- | lib/events/roommemberevent.h | 32 | ||||
-rw-r--r-- | lib/events/stateevent.cpp | 21 | ||||
-rw-r--r-- | lib/events/stateevent.h | 21 | ||||
-rw-r--r-- | quotest/quotest.cpp | 2 |
14 files changed, 203 insertions, 319 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c78a5981..a1b6f0c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,16 +21,21 @@ jobs: matrix: os: [ubuntu-20.04, macos-10.15] compiler: [ GCC, Clang ] - platform: [ '' ] qt-version: [ '5.12.10' ] - qt-arch: [ '' ] # Not using binary values here, to make the job captions more readable e2ee: [ '' ] update-api: [ '', 'update-api' ] + sonar: [ '' ] + platform: [ '' ] + qt-arch: [ '' ] exclude: - os: macos-10.15 compiler: GCC include: + - os: ubuntu-latest + compiler: GCC + qt-version: '5.12.10' + sonar: 'sonar' - os: windows-2019 compiler: MSVC platform: x64 @@ -43,6 +48,9 @@ jobs: qt-arch: win64_msvc2017_64 update-api: update-api + env: + SONAR_SERVER_URL: 'https://sonarcloud.io' + steps: - uses: actions/checkout@v2 with: @@ -96,9 +104,19 @@ jobs: VERSION="$(git describe --all --contains)-ci${{ github.run_number }}-$(git rev-parse --short HEAD)" fi echo "QUOTEST_ORIGIN=$VERSION @ ${{ runner.os }}/${{ matrix.compiler }}" >>$GITHUB_ENV - echo "CMAKE_ARGS=-G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=false \ - -DCMAKE_INSTALL_PREFIX=~/.local -DCMAKE_PREFIX_PATH=~/.local\ - -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON" >>$GITHUB_ENV + + CMAKE_ARGS="-G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DBUILD_SHARED_LIBS=false \ + -DCMAKE_INSTALL_PREFIX=~/.local \ + -DCMAKE_PREFIX_PATH=~/.local \ + -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON" + + if [ -n "${{ matrix.sonar }}" ]; then + mkdir -p $HOME/.sonar + CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_CXX_FLAGS=--coverage" + echo "COV=gcov$CXX_VERSION_POSTFIX" >>$GITHUB_ENV + fi + echo "CMAKE_ARGS=$CMAKE_ARGS" >>$GITHUB_ENV if [[ '${{ runner.os }}' != 'Windows' ]]; then BIN_DIR=/bin @@ -115,6 +133,20 @@ jobs: with: arch: ${{ matrix.platform }} + - name: Download and set up Sonar Cloud tools + if: matrix.sonar != '' + env: + SONAR_SCANNER_VERSION: 4.6.2.2472 + run: | + pushd $HOME/.sonar + curl -sSL --remote-name-all \ + $SONAR_SERVER_URL/static/cpp/build-wrapper-linux-x86.zip \ + https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_VERSION-linux.zip + unzip -o build-wrapper*.zip + echo "BUILD_WRAPPER=$HOME/.sonar/build-wrapper-linux-x86/build-wrapper-linux* --out-dir $BUILD_PATH/sonar" >>$GITHUB_ENV + unzip -o sonar-scanner-cli*.zip + popd + - name: Build and install olm if: matrix.e2ee working-directory: ${{ runner.workspace }} @@ -158,7 +190,8 @@ jobs: - name: Build and install libQuotient run: | - cmake --build $BUILD_PATH --target all install + $BUILD_WRAPPER cmake --build $BUILD_PATH --target all + cmake --build $BUILD_PATH --target install ls ~/.local$BIN_DIR/quotest - name: Run tests @@ -172,7 +205,26 @@ jobs: [[ -z "$TEST_USER" ]] || \ $VALGRIND quotest "$TEST_USER" "$TEST_PWD" quotest-gha '#quotest:matrix.org' "$QUOTEST_ORIGIN" timeout-minutes: 4 # quotest is supposed to finish within 3 minutes, actually - + - name: Perform CodeQL analysis if: env.CODEQL_ANALYSIS uses: github/codeql-action/analyze@v1 + + - name: Run sonar-scanner + if: matrix.sonar != '' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: | + mkdir .coverage && pushd .coverage + find $BUILD_PATH -name '*.gcda' -print0 \ + | xargs -0 $COV -s $GITHUB_WORKSPACE -pr + # Coverage of the test source code is not tracked, as it is always 100% + # (if not, some tests failed and broke the build at an earlier stage) + rm -f quotest* autotests* + popd + $HOME/.sonar/sonar-scanner*/bin/sonar-scanner \ + -Dsonar.host.url="$SONAR_SERVER_URL" \ + -Dsonar.cfamily.build-wrapper-output="$BUILD_PATH/sonar" \ + -Dsonar.cfamily.threads=2 \ + -Dsonar.cfamily.gcov.reportsPath=.coverage diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml deleted file mode 100644 index 76db59c9..00000000 --- a/.github/workflows/sonar.yml +++ /dev/null @@ -1,113 +0,0 @@ -name: Sonar - -on: - push: - pull_request: - types: [opened, reopened] - -defaults: - run: - shell: bash - -jobs: - SonarCloud: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - qt-version: [ '5.12.10' ] - e2ee: [ '', 'e2ee' ] - update-api: [ '', 'update-api' ] - - env: - SONAR_SCANNER_VERSION: 4.6.2.2472 - SONAR_SERVER_URL: "https://sonarcloud.io" - BUILD_WRAPPER_OUT_DIR: build/sonar - - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - submodules: ${{ matrix.e2ee != '' }} - - - name: Cache Qt - id: cache-qt - uses: actions/cache@v2 - with: - path: ${{ runner.workspace }}/Qt - key: ${{ runner.os }}-Qt${{ matrix.qt-version }}-cache - - - name: Install Qt - uses: jurplel/install-qt-action@v2.11.1 - with: - version: ${{ matrix.qt-version }} -# arch: ${{ matrix.qt-arch }} # Only Windows needs that - cached: ${{ steps.cache-qt.outputs.cache-hit }} - - - name: Install Ninja - uses: seanmiddleditch/gha-setup-ninja@v3 - - - name: Setup build environment - run: | - echo "CC=gcc-10" >>$GITHUB_ENV - echo "CXX=g++-10" >>$GITHUB_ENV - mkdir -p $HOME/.sonar - echo "CMAKE_ARGS=-G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=false \ - -DCMAKE_INSTALL_PREFIX=~/.local -DCMAKE_PREFIX_PATH=~/.local" >>$GITHUB_ENV - cmake -E make_directory ${{ runner.workspace }}/build - - - name: Build and install olm - if: matrix.e2ee - run: | - cd .. - git clone https://gitlab.matrix.org/matrix-org/olm.git - cmake -S olm -B olm/build $CMAKE_ARGS - cmake --build olm/build --target install - - - name: Pull CS API and build GTAD - if: matrix.update-api - run: | - cd .. - git clone https://github.com/quotient-im/matrix-doc.git - git clone --recursive https://github.com/KitsuneRal/gtad.git - cmake -S gtad -B gtad $CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF - cmake --build gtad - echo "CMAKE_ARGS=$CMAKE_ARGS -DMATRIX_DOC_PATH=$GITHUB_WORKSPACE/../matrix-doc \ - -DGTAD_PATH=$GITHUB_WORKSPACE/../gtad/gtad" \ - >>$GITHUB_ENV - - - name: Download and set up Sonar Cloud tools - run: | - pushd $HOME/.sonar - curl -sSLo build-wrapper.zip $SONAR_SERVER_URL/static/cpp/build-wrapper-linux-x86.zip - unzip -o build-wrapper.zip - echo "BUILD_WRAPPER=$HOME/.sonar/build-wrapper-linux-x86/build-wrapper-linux* --out-dir $BUILD_WRAPPER_OUT_DIR" >>$GITHUB_ENV - curl -sSLo sonar-scanner.zip \ - https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_VERSION-linux.zip - unzip -o sonar-scanner.zip - popd - - - name: Configure libQuotient - run: | - if [[ '${{ runner.os }}' == 'Windows' ]]; then - BIN_DIR=. - else - BIN_DIR=bin - fi - echo "BIN_DIR=$BIN_DIR" >>$GITHUB_ENV - cmake -S $GITHUB_WORKSPACE -B build $CMAKE_ARGS -DQuotient_ENABLE_E2EE=${{ matrix.e2ee }} - - - name: Regenerate API code - if: matrix.update-api - run: cmake --build build --target update-api - - - name: Build libQuotient - run: | - $BUILD_WRAPPER cmake --build build --target all - - - name: Run sonar-scanner - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: | - $HOME/.sonar/sonar-scanner*/bin/sonar-scanner --define sonar.host.url="${{ env.SONAR_SERVER_URL }}" --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" diff --git a/CMakeLists.txt b/CMakeLists.txt index 2762df6a..adb5be7b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -147,6 +147,7 @@ list(APPEND lib_SRCS lib/accountregistry.h lib/accountregistry.cpp lib/mxcreply.h lib/mxcreply.cpp lib/events/event.h lib/events/event.cpp + lib/events/eventloader.h lib/events/roomevent.h lib/events/roomevent.cpp lib/events/stateevent.h lib/events/stateevent.cpp lib/events/simplestateevents.h @@ -161,10 +162,10 @@ list(APPEND lib_SRCS lib/events/accountdataevents.h lib/events/receiptevent.h lib/events/receiptevent.cpp lib/events/reactionevent.h lib/events/reactionevent.cpp - lib/events/callanswerevent.h lib/events/callanswerevent.cpp - lib/events/callcandidatesevent.h lib/events/callcandidatesevent.cpp - lib/events/callhangupevent.h lib/events/callhangupevent.cpp lib/events/callinviteevent.h lib/events/callinviteevent.cpp + lib/events/callcandidatesevent.h + lib/events/callanswerevent.h lib/events/callanswerevent.cpp + lib/events/callhangupevent.h lib/events/directchatevent.h lib/events/directchatevent.cpp lib/events/encryptionevent.h lib/events/encryptionevent.cpp lib/events/encryptedevent.h lib/events/encryptedevent.cpp diff --git a/lib/events/callcandidatesevent.cpp b/lib/events/callcandidatesevent.cpp deleted file mode 100644 index b87c8e9b..00000000 --- a/lib/events/callcandidatesevent.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-FileCopyrightText: 2017 Marius Gripsgard <marius@ubports.com> -// SPDX-FileCopyrightText: 2018 Josip Delic <delijati@googlemail.com> -// SPDX-License-Identifier: LGPL-2.1-or-later - -#include "callcandidatesevent.h" - -/* -m.call.candidates -{ - "age": 242352, - "content": { - "call_id": "12345", - "candidates": [ - { - "candidate": "candidate:863018703 1 udp 2122260223 10.9.64.156 -43670 typ host generation 0", "sdpMLineIndex": 0, "sdpMid": "audio" - } - ], - "version": 0 - }, - "event_id": "$WLGTSEFSEF:localhost", - "origin_server_ts": 1431961217939, - "room_id": "!Cuyf34gef24t:localhost", - "sender": "@example:localhost", - "type": "m.call.candidates" -} -*/ diff --git a/lib/events/callhangupevent.cpp b/lib/events/callhangupevent.cpp deleted file mode 100644 index 43bc4db0..00000000 --- a/lib/events/callhangupevent.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/****************************************************************************** - * SPDX-FileCopyrightText: 2017 Marius Gripsgard <marius@ubports.com> - * SPDX-FileCopyrightText: 2018 Josip Delic <delijati@googlemail.com> - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#include "callhangupevent.h" - -/* -m.call.hangup -{ - "age": 242352, - "content": { - "call_id": "12345", - "version": 0 - }, - "event_id": "$WLGTSEFSEF:localhost", - "origin_server_ts": 1431961217939, - "room_id": "!Cuyf34gef24t:localhost", - "sender": "@example:localhost", - "type": "m.call.hangup" -} -*/ - -using namespace Quotient; - -CallHangupEvent::CallHangupEvent(const QJsonObject& obj) - : CallEventBase(typeId(), obj) -{ - qCDebug(EVENTS) << "Call Hangup event"; -} - -CallHangupEvent::CallHangupEvent(const QString& callId) - : CallEventBase(typeId(), matrixTypeId(), callId, 0) -{} diff --git a/lib/events/callhangupevent.h b/lib/events/callhangupevent.h index 24382ac2..f3f82833 100644 --- a/lib/events/callhangupevent.h +++ b/lib/events/callhangupevent.h @@ -11,8 +11,12 @@ class CallHangupEvent : public CallEventBase { public: DEFINE_EVENT_TYPEID("m.call.hangup", CallHangupEvent) - explicit CallHangupEvent(const QJsonObject& obj); - explicit CallHangupEvent(const QString& callId); + explicit CallHangupEvent(const QJsonObject& obj) + : CallEventBase(typeId(), obj) + {} + explicit CallHangupEvent(const QString& callId) + : CallEventBase(typeId(), matrixTypeId(), callId, 0) + {} }; REGISTER_EVENT_TYPE(CallHangupEvent) diff --git a/lib/events/event.h b/lib/events/event.h index 4d4bb16b..e786fb30 100644 --- a/lib/events/event.h +++ b/lib/events/event.h @@ -110,94 +110,90 @@ inline event_type_t typeId() inline event_type_t unknownEventTypeId() { return typeId<void>(); } -// === EventFactory === +// === Event creation facilities === -/** Create an event of arbitrary type from its arguments */ +//! Create an event of arbitrary type from its arguments template <typename EventT, typename... ArgTs> inline event_ptr_tt<EventT> makeEvent(ArgTs&&... args) { return std::make_unique<EventT>(std::forward<ArgTs>(args)...); } -template <typename BaseEventT> -class EventFactory { -public: - template <typename FnT> - static auto addMethod(FnT&& method) - { - factories().emplace_back(std::forward<FnT>(method)); - return 0; - } - - /** Chain two type factories - * Adds the factory class of EventT2 (EventT2::factory_t) to - * the list in factory class of EventT1 (EventT1::factory_t) so - * that when EventT1::factory_t::make() is invoked, types of - * EventT2 factory are looked through as well. This is used - * to include RoomEvent types into the more general Event factory, - * and state event types into the RoomEvent factory. - */ - template <typename EventT> - static auto chainFactory() - { - return addMethod(&EventT::factory_t::make); - } - - static event_ptr_tt<BaseEventT> make(const QJsonObject& json, - const QString& matrixType) - { - for (const auto& f : factories()) - if (auto e = f(json, matrixType)) - return e; - return nullptr; - } - -private: - static auto& factories() +namespace _impl { + template <class EventT, class BaseEventT> + event_ptr_tt<BaseEventT> makeIfMatches(const QJsonObject& json, + const QString& matrixType) { - using inner_factory_tt = std::function<event_ptr_tt<BaseEventT>( - const QJsonObject&, const QString&)>; - static std::vector<inner_factory_tt> _factories {}; - return _factories; + return QLatin1String(EventT::matrixTypeId()) == matrixType + ? makeEvent<EventT>(json) + : nullptr; } -}; - -/** Add a type to its default factory - * Adds a standard factory method (via makeEvent<>) for a given - * type to EventT::factory_t factory class so that it can be - * created dynamically from loadEvent<>(). - * - * \tparam EventT the type to enable dynamic creation of - * \return the registered type id - * \sa loadEvent, Event::type - */ -template <typename EventT> -inline auto setupFactory() -{ - qDebug(EVENTS) << "Adding factory method for" << EventT::matrixTypeId(); - return EventT::factory_t::addMethod([](const QJsonObject& json, - const QString& jsonMatrixType) { - return EventT::matrixTypeId() == jsonMatrixType ? makeEvent<EventT>(json) - : nullptr; - }); -} -template <typename EventT> -inline auto registerEventType() -{ - // Initialise exactly once, even if this function is called twice for - // the same type (for whatever reason - you never know the ways of - // static initialisation is done). - static const auto _ = setupFactory<EventT>(); - return _; // Only to facilitate usage in static initialisation -} + //! \brief A family of event factories to create events from CS API responses + //! + //! Each of these factories, as instantiated by event base types (Event, + //! RoomEvent etc.) is capable of producing an event object derived from + //! \p BaseEventT, using the JSON payload and the event type passed to its + //! make() method. Don't use these directly to make events; use loadEvent() + //! overloads as the frontend for these. Never instantiate new factories + //! outside of base event classes. + //! \sa loadEvent, setupFactory, Event::factory, RoomEvent::factory, + //! StateEventBase::factory + template <typename BaseEventT> + class EventFactory + : private std::vector<event_ptr_tt<BaseEventT> (*)(const QJsonObject&, + const QString&)> { + // Actual makeIfMatches specialisations will differ in the first + // template parameter but that doesn't affect the function type + public: + explicit EventFactory(const char* name = "") + : name(name) + { + static auto yetToBeConstructed = true; + Q_ASSERT(yetToBeConstructed); + if (!yetToBeConstructed) // For Release builds that pass Q_ASSERT + qCritical(EVENTS) + << "Another EventFactory for the same base type is being " + "created - event creation logic will be splintered"; + yetToBeConstructed = false; + } + EventFactory(const EventFactory&) = delete; + + //! \brief Add a method to create events of a given type + //! + //! Adds a standard factory method (makeIfMatches) for \p EventT so that + //! event objects of this type can be created dynamically by loadEvent. + //! The caller is responsible for ensuring this method is called only + //! once per type. + //! \sa makeIfMatches, loadEvent, Quotient::loadEvent + template <class EventT> + bool addMethod() + { + this->emplace_back(&makeIfMatches<EventT, BaseEventT>); + qDebug(EVENTS) << "Added factory method for" + << EventT::matrixTypeId() << "events;" << this->size() + << "methods in the" << name << "chain by now"; + return true; + } + + auto loadEvent(const QJsonObject& json, const QString& matrixType) + { + for (const auto& f : *this) + if (auto e = f(json, matrixType)) + return e; + return makeEvent<BaseEventT>(unknownEventTypeId(), json); + } + + const char* const name; + }; +} // namespace _impl // === Event === class Event { public: using Type = event_type_t; - using factory_t = EventFactory<Event>; + static inline _impl::EventFactory<Event> factory { "Event" }; explicit Event(Type type, const QJsonObject& json); explicit Event(Type type, event_mtype_t matrixType, @@ -272,7 +268,7 @@ template <typename EventT> using EventsArray = std::vector<event_ptr_tt<EventT>>; using Events = EventsArray<Event>; -// === Macros used with event class definitions === +// === Facilities for event class definitions === // This macro should be used in a public section of an event class to // provide matrixTypeId() and typeId(). @@ -284,13 +280,27 @@ using Events = EventsArray<Event>; // This macro should be put after an event class definition (in .h or .cpp) // to enable its deserialisation from a /sync and other // polymorphic event arrays -#define REGISTER_EVENT_TYPE(_Type) \ - namespace { \ - [[maybe_unused]] static const auto _factoryAdded##_Type = \ - registerEventType<_Type>(); \ - } \ +#define REGISTER_EVENT_TYPE(_Type) \ + [[maybe_unused]] inline const auto _factoryAdded##_Type = \ + _Type::factory.addMethod<_Type>(); \ // End of macro +// === Event loading === +// (see also event_loader.h) + +//! \brief Point of customisation to dynamically load events +//! +//! The default specialisation of this calls BaseEventT::factory and if that +//! fails (i.e. returns nullptr) creates an unknown event of BaseEventT. +//! Other specialisations may reuse other factories, add validations common to +//! BaseEventT, and so on +template <class BaseEventT> +event_ptr_tt<BaseEventT> doLoadEvent(const QJsonObject& json, + const QString& matrixType) +{ + return BaseEventT::factory.loadEvent(json, matrixType); +} + // === is<>(), eventCast<>() and switchOnType<>() === template <class EventT> diff --git a/lib/events/eventloader.h b/lib/events/eventloader.h index 978668f2..fe624d70 100644 --- a/lib/events/eventloader.h +++ b/lib/events/eventloader.h @@ -6,16 +6,6 @@ #include "stateevent.h" namespace Quotient { -namespace _impl { - template <typename BaseEventT> - static inline auto loadEvent(const QJsonObject& json, - const QString& matrixType) - { - if (auto e = EventFactory<BaseEventT>::make(json, matrixType)) - return e; - return makeEvent<BaseEventT>(unknownEventTypeId(), json); - } -} // namespace _impl /*! Create an event with proper type from a JSON object * @@ -26,7 +16,7 @@ namespace _impl { template <typename BaseEventT> inline event_ptr_tt<BaseEventT> loadEvent(const QJsonObject& fullJson) { - return _impl::loadEvent<BaseEventT>(fullJson, fullJson[TypeKeyL].toString()); + return doLoadEvent<BaseEventT>(fullJson, fullJson[TypeKeyL].toString()); } /*! Create an event from a type string and content JSON @@ -39,8 +29,8 @@ template <typename BaseEventT> inline event_ptr_tt<BaseEventT> loadEvent(const QString& matrixType, const QJsonObject& content) { - return _impl::loadEvent<BaseEventT>(basicEventJson(matrixType, content), - matrixType); + return doLoadEvent<BaseEventT>(basicEventJson(matrixType, content), + matrixType); } /*! Create a state event from a type string, content JSON and state key @@ -53,7 +43,7 @@ inline StateEventPtr loadStateEvent(const QString& matrixType, const QJsonObject& content, const QString& stateKey = {}) { - return _impl::loadEvent<StateEventBase>( + return doLoadEvent<StateEventBase>( basicStateEventJson(matrixType, content, stateKey), matrixType); } diff --git a/lib/events/roomevent.cpp b/lib/events/roomevent.cpp index fb921af6..b728e0bf 100644 --- a/lib/events/roomevent.cpp +++ b/lib/events/roomevent.cpp @@ -9,9 +9,6 @@ using namespace Quotient; -[[maybe_unused]] static auto roomEventTypeInitialised = - Event::factory_t::chainFactory<RoomEvent>(); - RoomEvent::RoomEvent(Type type, event_mtype_t matrixType, const QJsonObject& contentJson) : Event(type, matrixType, contentJson) diff --git a/lib/events/roomevent.h b/lib/events/roomevent.h index 7f13f6f2..8be58481 100644 --- a/lib/events/roomevent.h +++ b/lib/events/roomevent.h @@ -13,7 +13,7 @@ class RedactionEvent; /** This class corresponds to m.room.* events */ class RoomEvent : public Event { public: - using factory_t = EventFactory<RoomEvent>; + static inline _impl::EventFactory<RoomEvent> factory { "RoomEvent" }; // RedactionEvent is an incomplete type here so we cannot inline // constructors and destructors and we cannot use 'using'. diff --git a/lib/events/roommemberevent.h b/lib/events/roommemberevent.h index f3047159..0fb464d4 100644 --- a/lib/events/roommemberevent.h +++ b/lib/events/roommemberevent.h @@ -49,16 +49,15 @@ public: std::forward<ArgTs>(contentArgs)...) {} - /// A special constructor to create unknown RoomMemberEvents - /** - * This is needed in order to use RoomMemberEvent as a "base event - * class" in cases like GetMembersByRoomJob when RoomMemberEvents - * (rather than RoomEvents or StateEvents) are resolved from JSON. - * For such cases loadEvent<> requires an underlying class to be - * constructible with unknownTypeId() instead of its genuine id. - * Don't use it directly. - * \sa GetMembersByRoomJob, loadEvent, unknownTypeId - */ + //! \brief A special constructor to create unknown RoomMemberEvents + //! + //! This is needed in order to use RoomMemberEvent as a "base event class" + //! in cases like GetMembersByRoomJob when RoomMemberEvents (rather than + //! RoomEvents or StateEvents) are resolved from JSON. For such cases + //! loadEvent\<> requires an underlying class to have a specialisation of + //! EventFactory\<> and be constructible with unknownTypeId() instead of + //! its genuine id. Don't use directly. + //! \sa EventFactory, loadEvent, GetMembersByRoomJob RoomMemberEvent(Type type, const QJsonObject& fullJson) : StateEvent(type, fullJson) {} @@ -89,14 +88,13 @@ public: }; template <> -class EventFactory<RoomMemberEvent> { -public: - static event_ptr_tt<RoomMemberEvent> make(const QJsonObject& json, - const QString&) - { +inline event_ptr_tt<RoomMemberEvent> +doLoadEvent<RoomMemberEvent>(const QJsonObject& json, const QString& matrixType) +{ + if (matrixType == QLatin1String(RoomMemberEvent::matrixTypeId())) return makeEvent<RoomMemberEvent>(json); - } -}; + return makeEvent<RoomMemberEvent>(unknownEventTypeId(), json); +} REGISTER_EVENT_TYPE(RoomMemberEvent) } // namespace Quotient diff --git a/lib/events/stateevent.cpp b/lib/events/stateevent.cpp index efe011a0..e53d47d4 100644 --- a/lib/events/stateevent.cpp +++ b/lib/events/stateevent.cpp @@ -5,20 +5,13 @@ using namespace Quotient; -// Aside from the normal factory to instantiate StateEventBase inheritors -// StateEventBase itself can be instantiated if there's a state_key JSON key -// but the event type is unknown. -[[maybe_unused]] static auto stateEventTypeInitialised = - RoomEvent::factory_t::addMethod( - [](const QJsonObject& json, const QString& matrixType) -> StateEventPtr { - if (!json.contains(StateKeyKeyL)) - return nullptr; - - if (auto e = StateEventBase::factory_t::make(json, matrixType)) - return e; - - return makeEvent<StateEventBase>(unknownEventTypeId(), json); - }); +StateEventBase::StateEventBase(Type type, const QJsonObject& json) + : RoomEvent(json.contains(StateKeyKeyL) ? type : unknownEventTypeId(), json) +{ + if (Event::type() == unknownEventTypeId() && !json.contains(StateKeyKeyL)) + qWarning(EVENTS) << "Attempt to create a state event with no stateKey -" + "forcing the event type to unknown to avoid damage"; +} StateEventBase::StateEventBase(Event::Type type, event_mtype_t matrixType, const QString& stateKey, diff --git a/lib/events/stateevent.h b/lib/events/stateevent.h index b0aa9907..c37965aa 100644 --- a/lib/events/stateevent.h +++ b/lib/events/stateevent.h @@ -19,10 +19,9 @@ inline QJsonObject basicStateEventJson(const QString& matrixTypeId, class StateEventBase : public RoomEvent { public: - using factory_t = EventFactory<StateEventBase>; + static inline _impl::EventFactory<StateEventBase> factory { "StateEvent" }; - StateEventBase(Type type, const QJsonObject& json) : RoomEvent(type, json) - {} + StateEventBase(Type type, const QJsonObject& json); StateEventBase(Type type, event_mtype_t matrixType, const QString& stateKey = {}, const QJsonObject& contentJson = {}); @@ -37,6 +36,22 @@ public: using StateEventPtr = event_ptr_tt<StateEventBase>; using StateEvents = EventsArray<StateEventBase>; +//! \brief Override RoomEvent factory with that from StateEventBase if JSON has +//! stateKey +//! +//! This means in particular that an event with a type known to RoomEvent but +//! having stateKey set (even to an empty value) will be treated as a state +//! event and most likely end up as unknown (consider, e.g., m.room.message +//! that has stateKey set). +template <> +inline RoomEventPtr doLoadEvent(const QJsonObject& json, + const QString& matrixType) +{ + if (json.contains(StateKeyKeyL)) + return StateEventBase::factory.loadEvent(json, matrixType); + return RoomEvent::factory.loadEvent(json, matrixType); +} + template <> inline bool is<StateEventBase>(const Event& e) { diff --git a/quotest/quotest.cpp b/quotest/quotest.cpp index 8703efb2..7bd9c5c3 100644 --- a/quotest/quotest.cpp +++ b/quotest/quotest.cpp @@ -214,7 +214,7 @@ TestManager::TestManager(int& argc, char** argv) // Big countdown watchdog QTimer::singleShot(180000, this, [this] { - clog << "Time is up, stopping the session"; + clog << "Time is up, stopping the session\n"; if (testSuite) conclude(); else |