aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml66
-rw-r--r--.github/workflows/sonar.yml113
-rw-r--r--CMakeLists.txt7
-rw-r--r--lib/events/callcandidatesevent.cpp27
-rw-r--r--lib/events/callhangupevent.cpp36
-rw-r--r--lib/events/callhangupevent.h8
-rw-r--r--lib/events/event.h166
-rw-r--r--lib/events/eventloader.h18
-rw-r--r--lib/events/roomevent.cpp3
-rw-r--r--lib/events/roomevent.h2
-rw-r--r--lib/events/roommemberevent.h32
-rw-r--r--lib/events/stateevent.cpp21
-rw-r--r--lib/events/stateevent.h21
-rw-r--r--quotest/quotest.cpp2
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