From 8d21c8a6579ad9c63e331ffb42e3ed81b9c73caf Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Tue, 24 Aug 2021 23:59:48 +0200 Subject: Add AccountRegistry Basic session management class; Created from Quaternion's AccountRegistry and NeoChat's AccountListModel. The connections can be accessed by the user's id, this technically limits it to one connection for each matrix account. --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'CMakeLists.txt') diff --git a/CMakeLists.txt b/CMakeLists.txt index 49105389..3c6e7548 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,6 +140,7 @@ list(APPEND lib_SRCS lib/util.cpp lib/encryptionmanager.cpp lib/eventitem.cpp + lib/accountregistry.cpp lib/events/event.cpp lib/events/roomevent.cpp lib/events/stateevent.cpp -- cgit v1.2.3 From e2de07628f61c565ac8c85fa3aae84a5fa6feba3 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Tue, 31 Aug 2021 15:06:46 +0200 Subject: Add functions and macros to query for Quotient's version --- CMakeLists.txt | 4 ++++ lib/util.cpp | 20 ++++++++++++++++++++ lib/util.h | 5 +++++ 3 files changed, 29 insertions(+) (limited to 'CMakeLists.txt') diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c6e7548..aca1f982 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -275,6 +275,10 @@ file(GLOB_RECURSE api_SRCS ${add_CONFIGURE_DEPENDS} ${FULL_CSAPI_DIR}/*.cpp) add_library(${PROJECT_NAME} ${lib_SRCS} ${api_SRCS}) target_compile_definitions(${PROJECT_NAME} PRIVATE QT_NO_JAVA_STYLE_ITERATORS QT_NO_URL_CAST_FROM_STRING QT_NO_CAST_TO_ASCII) + +target_compile_definitions(${PROJECT_NAME} PUBLIC ${PROJECT_NAME}_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} + ${PROJECT_NAME}_VERSION_MINOR=${PROJECT_VERSION_MINOR} ${PROJECT_NAME}_VERSION_PATCH=${PROJECT_VERSION_PATCH} + ${PROJECT_NAME}_VERSION_STRING=\"${PROJECT_VERSION}\") if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.16.0" AND NOT CMAKE_CXX_COMPILER_ID STREQUAL GNU) # https://bugzilla.redhat.com/show_bug.cgi?id=1721553 target_precompile_headers(${PROJECT_NAME} PRIVATE lib/converters.h) diff --git a/lib/util.cpp b/lib/util.cpp index 904bfd5a..3de1d169 100644 --- a/lib/util.cpp +++ b/lib/util.cpp @@ -119,6 +119,26 @@ QString Quotient::serverPart(const QString& mxId) return parser.match(mxId).captured(1); } +QString Quotient::versionString() +{ + return QStringLiteral(Quotient_VERSION_STRING); +} + +int Quotient::majorVersion() +{ + return Quotient_VERSION_MAJOR; +} + +int Quotient::minorVersion() +{ + return Quotient_VERSION_MINOR; +} + +int Quotient::patchVersion() +{ + return Quotient_VERSION_PATCH; +} + // Tests for function_traits<> using namespace Quotient; diff --git a/lib/util.h b/lib/util.h index 78fc9ab7..5bfe6841 100644 --- a/lib/util.h +++ b/lib/util.h @@ -318,4 +318,9 @@ qreal stringToHueF(const QString& s); /** Extract the serverpart from MXID */ QString serverPart(const QString& mxId); + +QString versionString(); +int majorVersion(); +int minorVersion(); +int patchVersion(); } // namespace Quotient -- cgit v1.2.3 From db9dd0ea43f2140e0df72d05861939ee1cb98053 Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Wed, 1 Sep 2021 17:06:41 +0200 Subject: CMakeLists: fix resolving gtad on Windows --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'CMakeLists.txt') diff --git a/CMakeLists.txt b/CMakeLists.txt index 49105389..5e5c1932 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -176,7 +176,7 @@ set(ASAPI_DEF_DIR application-service/definitions) set(ISAPI_DEF_DIR identity/definitions) if (GTAD_PATH AND MATRIX_DOC_PATH) - get_filename_component(ABS_GTAD_PATH "${GTAD_PATH}" REALPATH) + get_filename_component(ABS_GTAD_PATH "${GTAD_PATH}" PROGRAM PROGRAM_ARGS GTAD_ARGS) if (EXISTS ${ABS_GTAD_PATH}) get_filename_component(ABS_API_DEF_PATH "${MATRIX_DOC_PATH}/data/api" REALPATH) if (NOT IS_DIRECTORY ${ABS_API_DEF_PATH}) @@ -227,6 +227,7 @@ if (API_GENERATION_ENABLED) old_sync.yaml- room_initial_sync.yaml- # deprecated key_backup.yaml- # immature and buggy in terms of API definition sync.yaml- # we have a better handcrafted implementation + ${GTAD_ARGS} WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/lib SOURCES gtad/gtad.yaml gtad/data.h.mustache -- cgit v1.2.3 From 87d05252acc4ed94d24150eabb2dd1a1f700f46f Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Wed, 1 Sep 2021 17:08:48 +0200 Subject: CMakeLists: allow to pass clang-format options in CLANG_FORMAT This supersedes passing clang-format options in a separate CLANG_FORMAT_ARGS CMake variable. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'CMakeLists.txt') diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e5c1932..22951faa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -198,7 +198,7 @@ if (API_GENERATION_ENABLED) if (NOT CLANG_FORMAT) set(CLANG_FORMAT clang-format) endif() - get_filename_component(ABS_CLANG_FORMAT "${CLANG_FORMAT}" PROGRAM) + get_filename_component(ABS_CLANG_FORMAT "${CLANG_FORMAT}" PROGRAM PROGRAM_ARGS CLANG_FORMAT_ARGS) if (ABS_CLANG_FORMAT) set(API_FORMATTING_ENABLED 1) message( STATUS "clang-format is at ${ABS_CLANG_FORMAT}") -- cgit v1.2.3 From f14b04157a9cacaf60f815f164939cc42dad04da Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Thu, 2 Sep 2021 19:42:24 +0200 Subject: Require CMake 3.16; drop qmake; use C++20 and newer compilers Also, refresh the documentation a bit. --- CMakeLists.txt | 30 +++++++------- CONTRIBUTING.md | 2 +- README.md | 125 +++++++++++++++++++++++++------------------------------- 3 files changed, 72 insertions(+), 85 deletions(-) (limited to 'CMakeLists.txt') diff --git a/CMakeLists.txt b/CMakeLists.txt index 62fa43de..c0a39932 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.16) if (POLICY CMP0092) cmake_policy(SET CMP0092 NEW) endif() @@ -207,15 +207,14 @@ if (API_GENERATION_ENABLED) message( STATUS "${CLANG_FORMAT} is NOT FOUND; API files won't be reformatted") endif () - if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.12.0") - # We use globbing with CONFIGURE_DEPENDS to produce two file lists: - # one of all API files for clang-format and another of just .cpp - # files to supply for library source files. Since we expect these - # file lists to only change due to GTAD invocation, we only use - # CONFIGURE_DEPENDS when pre-requisites to update API are met. - # Read comments next to each file(GLOB_RECURSE) for caveats. - set(add_CONFIGURE_DEPENDS "CONFIGURE_DEPENDS") - endif() + # We use globbing with CONFIGURE_DEPENDS to produce two file lists: + # one of all API files for clang-format and another of just .cpp + # files to supply for library source files. Since we expect these + # file lists to only change due to GTAD invocation, we only use + # CONFIGURE_DEPENDS when pre-requisites to update API are met. + # Read comments next to each file(GLOB_RECURSE) for caveats. + set(add_CONFIGURE_DEPENDS "CONFIGURE_DEPENDS") + set(FULL_CSAPI_SRC_DIR ${ABS_API_DEF_PATH}/client-server) file(GLOB_RECURSE API_DEFS RELATIVE ${PROJECT_SOURCE_DIR} ${FULL_CSAPI_SRC_DIR}/*.yaml @@ -280,14 +279,12 @@ target_compile_definitions(${PROJECT_NAME} PRIVATE QT_NO_JAVA_STYLE_ITERATORS QT target_compile_definitions(${PROJECT_NAME} PUBLIC ${PROJECT_NAME}_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} ${PROJECT_NAME}_VERSION_MINOR=${PROJECT_VERSION_MINOR} ${PROJECT_NAME}_VERSION_PATCH=${PROJECT_VERSION_PATCH} ${PROJECT_NAME}_VERSION_STRING=\"${PROJECT_VERSION}\") -if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.16.0" - AND NOT CMAKE_CXX_COMPILER_ID STREQUAL GNU) # https://bugzilla.redhat.com/show_bug.cgi?id=1721553 - target_precompile_headers(${PROJECT_NAME} PRIVATE lib/converters.h) -endif () if (${PROJECT_NAME}_ENABLE_E2EE) target_compile_definitions(${PROJECT_NAME} PUBLIC ${PROJECT_NAME}_E2EE_ENABLED) endif() set_target_properties(${PROJECT_NAME} PROPERTIES + CXX_STANDARD 20 + CXX_EXTENSIONS OFF VERSION "${PROJECT_VERSION}" SOVERSION ${API_VERSION} INTERFACE_${PROJECT_NAME}_MAJOR_VERSION ${API_VERSION} @@ -295,8 +292,13 @@ set_target_properties(${PROJECT_NAME} PROPERTIES set_property(TARGET ${PROJECT_NAME} APPEND PROPERTY COMPATIBLE_INTERFACE_STRING ${PROJECT_NAME}_MAJOR_VERSION) +# C++17 required, C++20 desired (see above) target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17) +if (NOT CMAKE_CXX_COMPILER_ID STREQUAL GNU) # https://bugzilla.redhat.com/show_bug.cgi?id=1721553 + target_precompile_headers(${PROJECT_NAME} PRIVATE lib/converters.h) +endif () + target_include_directories(${PROJECT_NAME} PUBLIC $ $ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4fdab602..c9296df1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -408,7 +408,7 @@ I (Kitsune) will be very glad to help you out. The types map in `gtad.yaml` is the central switchboard when it comes to matching OpenAPI types with C++ (and Qt) ones. It uses the following type attributes aside from pretty obvious "imports:": * `avoidCopy` - this attribute defines whether a const ref should be used instead of a value. For basic types like int this is obviously unnecessary; but compound types like `QVector` should rather be taken by reference when possible. * `moveOnly` - some types are not copyable at all and must be moved instead (an obvious example is anything "tainted" with a member of type `std::unique_ptr<>`). The template will use `T&&` instead of `T` or `const T&` to pass such types around. -* `useOmittable` - wrap types that have no value with "null" semantics (i.e. number types and custom-defined data structures) into a special `Omittable<>` template defined in `converters.h` - a substitute for `std::optional` from C++17 (we're still at C++14 yet). +* `useOmittable` - wrap types that have no value with "null" semantics (i.e. number types and custom-defined data structures) into a special `Omittable<>` template defined in `converters.h`, a drop-in upgrade over `std::optional`. * `omittedValue` - an alternative for `useOmittable`, just provide a value used for an omitted parameter. This is used for bool parameters which normally are considered false if omitted (or they have an explicit default value, passed in the "official" GTAD's `defaultValue` variable). * `initializer` - this is a _partial_ (see GTAD and Mustache documentation for explanations but basically it's a variable that is a Mustache template itself) that specifies how exactly a default value should be passed to the parameter. E.g., the default value for a `QString` parameter is enclosed into `QStringLiteral`. diff --git a/README.md b/README.md index 05c629f2..71f2d04c 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,7 @@ The Quotient project aims to produce a Qt5-based SDK to develop applications for [Matrix](https://matrix.org). libQuotient is a library that enables client applications. It is the backbone of [Quaternion](https://github.com/quotient-im/Quaternion), -[Spectral](https://matrix.org/docs/projects/client/spectral.html) and -other projects. +[NeoChat](https://matrix.org/docs/projects/client/neo-chat) and other projects. Versions 0.5.x and older use the previous name - libQMatrixClient. ## Contacts @@ -38,61 +37,62 @@ and bundle it with your application. ### Pre-requisites - A recent Linux, macOS or Windows system (desktop versions are known to work; mobile operating systems where Qt is available might work too) - - Recent enough Linux examples: Debian Buster; Fedora 28; openSUSE Leap 15; - Ubuntu Bionic Beaver. -- Qt 5 (either Open Source or Commercial), 5.9 or higher; - 5.12 is recommended, especially if you use qmake -- A build configuration tool (CMake is recommended, qmake is supported): - - CMake 3.10 or newer (from your package management system or - [the official website](https://cmake.org/download/)) - - or qmake (comes with Qt) -- A C++ toolchain with _reasonably complete_ C++17 support: - - GCC 7 (Windows, Linux, macOS), Clang 6 (Linux), Apple Clang 10 (macOS) - and Visual Studio 2017 (Windows) are the oldest officially supported. -- Any build system that works with CMake and/or qmake should be fine: - GNU Make, ninja (any platform), NMake, jom (Windows) are known to work. + - Recent enough Linux examples: Debian Bullseye; Fedora 33; openSUSE Leap 15.3; + Ubuntu Focal Fossa. +- Qt 5 (either Open Source or Commercial), 5.12 or higher +- CMake 3.16 or newer (from your package management system or + [the official website](https://cmake.org/download/)) +- A C++ toolchain with complete (as much as possible) C++17 and basic C++20: + - GCC 10 (Windows, Linux, macOS), Clang 11 (Linux), Apple Clang 12 (macOS) + and Visual Studio 2019 (Windows) are the oldest officially supported. +- Any build system that works with CMake should be fine: + GNU Make and ninja on any platform, NMake and jom on Windows are known to work. + Ninja is recommended. #### Linux -Just install things from the list above using your preferred package manager. If your Qt package base is fine-grained you might want to run cmake/qmake and look at error messages. The library is entirely offscreen (QtCore and QtNetwork are essential) but it also depends on QtGui in order to handle avatar thumbnails. +Just install things from the list above using your preferred package manager. +If your Qt package base is fine-grained you might want to run cmake and look +at error messages. The library is entirely offscreen but aside from QtCore and +QtNetwork it also depends on QtGui in order to handle avatar thumbnails. #### macOS -`brew install qt5` should get you a recent Qt5. If you plan to use CMake, you will need to tell it about the path to Qt by passing `-DCMAKE_PREFIX_PATH=$(brew --prefix qt5)` +`brew install qt5` should get you a recent Qt5. You may need to pass +`-DCMAKE_PREFIX_PATH=$(brew --prefix qt5)` to make it aware of the Qt location. #### Windows -Install Qt5, using their official installer; if you plan to build with CMake, -make sure to tick the CMake box in the list of installed components. - -The commands in further sections imply that cmake/qmake is in your PATH, -otherwise you have to prepend those commands with actual paths. As an option -it's a good idea to run a `qtenv2.bat` script that can be found in -`C:\Qt\\\bin` (assuming you installed Qt to `C:\Qt`); -the only thing it does is adding necessary paths to PATH. You might not want -to run that script on system startup but it's very handy to setup -the environment before building. For CMake you can alternatively point -`CMAKE_PREFIX_PATH` to your Qt installation and leave PATH unchanged; but -in that case you'll have to supply the full path to CMake when calling it. +Install Qt5 using their official installer; make sure to tick the CMake box +in the list of installed components unless you already have it installed. + +The commands in further sections imply that cmake is in your PATH, otherwise +you have to prepend those commands with actual paths. It's a good idea to run +a `qtenv2.bat` script that can be found in `C:\Qt\\\bin` +(assuming you installed Qt to `C:\Qt`) if you're building from the command line; +the script adds necessary paths to PATH. You might not want to run that script +on system startup but it's very handy to setup the environment before building. +Alternatively you can add the Qt path to `CMAKE_PREFIX_PATH` and leave PATH +unchanged. ### Using the library -If you use CMake, `find_package(Quotient)` sets up the client code to use -libQuotient, assuming the library development files are installed. There's no -documented procedure to use a preinstalled library with qmake; consider -introducing a submodule in your source tree and build it along with the rest -of the application for now. Note also that qmake is considered for phase-out -in Qt 6 so you should probably think of moving over to CMake eventually. +If you're just starting a project using libQuotient from scratch, you can copy +`quotest/CMakeLists.txt` to your project and change `quotest` to your +project name. If you already have an existing CMakeLists.txt, you need to insert +a `find_package(Quotient REQUIRED)` line to an appropriate place in it (use +`find_package(Quotient)` if libQuotient is not a hard dependency for you) and +then add `Quotient` to your `target_link_libraries()` line. Building with dynamic linkage is only tested on Linux at the moment and is a recommended way of linking your application with libQuotient on this platform. Static linkage is the default on Windows/macOS; feel free to experiment with dynamic linking and submit PRs if you get reusable results. -[Quotest](quotest), the test application that comes with libQuotient, includes -most common use cases such as sending messages, uploading files, -setting room state etc.; for more extensive usage check out the source code -of [Quaternion](https://github.com/quotient-im/Quaternion) -(the reference client of Quotient) or [Spectral](https://gitlab.com/b0/spectral). - -To ease the first step, `quotest/CMakeLists.txt` is a good starting point -for your own CMake-based project using libQuotient. +As for the actual API usage, a (very basic) overview can be found at +[the respective wiki page](https://github.com/quotient-im/libQuotient/wiki/libQuotient-overview). +Beyond that, looking at [Quotest](quotest) - the test application that comes +with libQuotient - may help you with most common use cases such as sending +messages, uploading files, setting room state etc. For more extensive usage +feel free to check out (and copy, with appropriate attribution) the source code +of [Quaternion](https://github.com/quotient-im/Quaternion) (the reference client +for libQuotient) or [NeoChat](https://invent.kde.org/network/neochat). ## Building the library [The source code is at GitHub](https://github.com/quotient-im/libQuotient). @@ -101,28 +101,29 @@ along with submodules is strongly recommended. If you want to hack on the library as a part of another project (e.g. you are working on Quaternion but need to do some changes to the library code), it makes sense to make a recursive check out of that project (in this case, Quaternion) -and update the library submodule (also recursively) to its master branch. +and update the library submodule (also recursively) within the appropriate +branch. Be mindful of API compatibility restrictions: e.g., Quaternion 0.0.95 +will not build with the master branch of libQuotient. Tags consisting of digits and periods represent released versions; tags ending with `-betaN` or `-rcN` mark pre-releases. If/when packaging pre-releases, it is advised to replace a dash with a tilde. -### CMake-based -In the root directory of the project sources: +The following commands issued in the root directory of the project sources: ```shell script mkdir build_dir cd build_dir cmake .. # [-D=...], see below cmake --build . --target all ``` -This will get you the compiled library in `build_dir` inside your project -sources. Static builds are tested on all supported platforms, building -the library as a shared object (aka dynamic library) is supported on Linux -and macOS but is very likely to be broken on Windows. - -The first CMake invocation configures the build. You can pass CMake variables, -such as `-DCMAKE_PREFIX_PATH="path1;path2;..."` and -`-DCMAKE_INSTALL_PREFIX=path` here if needed. +will get you a compiled library in `build_dir` inside your project sources. +Static builds are tested on all supported platforms, building the library as +a shared object (aka dynamic library) is supported on Linux and macOS but is +very likely to be broken on Windows. + +The first CMake invocation above configures the build. You can pass CMake +variables (such as `-DCMAKE_PREFIX_PATH="path1;path2;..."` and +`-DCMAKE_INSTALL_PREFIX=path`) here if needed. [CMake documentation](https://cmake.org/cmake/help/latest/index.html) (pick the CMake version at the top of the page that you use) describes the standard variables coming with CMake. On top of them, Quotient introduces: @@ -160,22 +161,6 @@ with the _installed_ library. Installation of the `quotest` binary along with the rest of the library can be skipped by setting `Quotient_INSTALL_TESTS` to `OFF`. -### qmake-based -The library provides a .pri file with an intention to be included from a bigger project's .pro file. As a starting point you can use `quotest.pro` that will build a minimal example of library usage for you. In the root directory of the project sources: -```shell script -qmake quotest.pro -make all -``` -This will get you `debug/quotest` and `release/quotest` -console executables that login to the Matrix server at matrix.org with -credentials of your choosing (pass the username and password as arguments), -run a sync long-polling loop and do some tests of the library API. Note that -qmake didn't really know about C++17 until Qt 5.12 so if your Qt is older -you may have quite a bit of warnings during the compilation process. - -Installing the standalone library with qmake is not implemented yet; PRs are -welcome though. - ## Troubleshooting #### Building fails -- cgit v1.2.3 From df66314bb47f1a824f35e9d5c7764305a4f103cb Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Fri, 3 Sep 2021 07:20:27 +0200 Subject: Tacitly allow CMake 3.13 to keep LGTM working Also: drop olm from the LGTM build environment, it's of no use there for now. --- .lgtm.yml | 18 ++++++++---------- CMakeLists.txt | 9 +++++++-- 2 files changed, 15 insertions(+), 12 deletions(-) (limited to 'CMakeLists.txt') diff --git a/.lgtm.yml b/.lgtm.yml index f6dfb229..308675a8 100644 --- a/.lgtm.yml +++ b/.lgtm.yml @@ -6,15 +6,13 @@ path_classifiers: extraction: cpp: prepare: - packages: # Assuming package base of cosmic - - ninja-build - - qt5-default + packages: # Assuming package base of eoan - qtmultimedia5-dev - after_prepare: - - git clone https://gitlab.matrix.org/matrix-org/olm.git - - pushd olm - - cmake . -Bbuild -GNinja - - cmake --build build - - popd +# after_prepare: +# - git clone https://gitlab.matrix.org/matrix-org/olm.git +# - pushd olm +# - cmake . -Bbuild -GNinja +# - cmake --build build +# - popd configure: - command: "cmake . -GNinja -DOlm_DIR=olm/build" + command: "cmake . -GNinja" # -DOlm_DIR=olm/build" diff --git a/CMakeLists.txt b/CMakeLists.txt index c0a39932..7043a653 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,6 @@ -cmake_minimum_required(VERSION 3.16) +# Officially CMake 3.16+ is needed but LGTM.com still sits on eoan that only +# has CMake 3.13 +cmake_minimum_required(VERSION 3.13) if (POLICY CMP0092) cmake_policy(SET CMP0092 NEW) endif() @@ -295,7 +297,10 @@ set_property(TARGET ${PROJECT_NAME} APPEND PROPERTY # C++17 required, C++20 desired (see above) target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17) -if (NOT CMAKE_CXX_COMPILER_ID STREQUAL GNU) # https://bugzilla.redhat.com/show_bug.cgi?id=1721553 +# TODO: Bump the CMake requirement and drop the version check here once +# LGTM upgrades +if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.16.0" + AND NOT CMAKE_CXX_COMPILER_ID STREQUAL GNU) # https://bugzilla.redhat.com/show_bug.cgi?id=1721553 target_precompile_headers(${PROJECT_NAME} PRIVATE lib/converters.h) endif () -- cgit v1.2.3 From 4bab0f2ef2c68b478d669f90557d6bef6332e823 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Tue, 31 Aug 2021 21:47:10 +0200 Subject: Implement the mxc protocol in the NetworkAccessManager Allows images to be loaded using the NetworkAccessManager instead of an ImageProvider --- CMakeLists.txt | 1 + lib/mxcreply.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++ lib/mxcreply.h | 29 +++++++++++++++++++++++ lib/networkaccessmanager.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++++ lib/networkaccessmanager.h | 6 +++++ 5 files changed, 146 insertions(+) create mode 100644 lib/mxcreply.cpp create mode 100644 lib/mxcreply.h (limited to 'CMakeLists.txt') diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c6e7548..178602da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,6 +141,7 @@ list(APPEND lib_SRCS lib/encryptionmanager.cpp lib/eventitem.cpp lib/accountregistry.cpp + lib/mxcreply.cpp lib/events/event.cpp lib/events/roomevent.cpp lib/events/stateevent.cpp diff --git a/lib/mxcreply.cpp b/lib/mxcreply.cpp new file mode 100644 index 00000000..49ebe603 --- /dev/null +++ b/lib/mxcreply.cpp @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: Tobias Fella +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "mxcreply.h" + +#include +#include "connection.h" +#include "room.h" +#include "networkaccessmanager.h" +#include "events/stickerevent.h" + +using namespace Quotient; + +class MxcReply::Private +{ +public: + QNetworkReply *m_reply = nullptr; +}; + +MxcReply::MxcReply(QNetworkReply* reply) +{ + reply->setParent(this); + d->m_reply = reply; + connect(d->m_reply, &QNetworkReply::finished, this, [this]() { + setError(d->m_reply->error(), d->m_reply->errorString()); + Q_EMIT finished(); + }); +} + +MxcReply::MxcReply(QNetworkReply* reply, Room* room, const QString &eventId) + : d(std::make_unique()) +{ + reply->setParent(this); + d->m_reply = reply; + connect(d->m_reply, &QNetworkReply::finished, this, [this, eventId]() { + setError(d->m_reply->error(), d->m_reply->errorString()); + Q_EMIT finished(); + }); +} + +bool MxcReply::isSequential() const +{ + return true; +} + +qint64 MxcReply::readData(char *data, qint64 maxSize) +{ + return d->m_reply->read(data, maxSize); +} + +void MxcReply::abort() +{ + d->m_reply->abort(); +} \ No newline at end of file diff --git a/lib/mxcreply.h b/lib/mxcreply.h new file mode 100644 index 00000000..26dea2d0 --- /dev/null +++ b/lib/mxcreply.h @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: Tobias Fella +// SPDX-License-Identifier: LGPL-2.1-or-later + +#pragma once + +#include +#include + +namespace Quotient { +class Room; +class Connection; +class MxcReply : public QNetworkReply +{ +public: + MxcReply(QNetworkReply* reply, Room* room, const QString &eventId); + MxcReply(QNetworkReply* reply); + + bool isSequential() const override; + +public slots: + void abort() override; + +protected: + qint64 readData(char *data, qint64 maxSize) override; +private: + class Private; + std::unique_ptr d; +}; +} \ No newline at end of file diff --git a/lib/networkaccessmanager.cpp b/lib/networkaccessmanager.cpp index a94ead34..e4132957 100644 --- a/lib/networkaccessmanager.cpp +++ b/lib/networkaccessmanager.cpp @@ -5,6 +5,11 @@ #include #include +#include "accountregistry.h" +#include "mxcreply.h" +#include "connection.h" + +#include "room.h" using namespace Quotient; @@ -56,7 +61,58 @@ NetworkAccessManager::~NetworkAccessManager() = default; QNetworkReply* NetworkAccessManager::createRequest( Operation op, const QNetworkRequest& request, QIODevice* outgoingData) { + if(request.url().scheme() == QStringLiteral("mxc")) { + const auto fragment = request.url().fragment(); + const auto fragmentParts = fragment.split(QLatin1Char('/')); + const auto mediaId = request.url().toString(QUrl::RemoveScheme | QUrl::RemoveFragment); + if(fragmentParts.size() == 3) { + auto connection = AccountRegistry::instance().get(fragmentParts[0]); + if(!connection) { + qWarning() << "Connection not found"; + return nullptr; + } + auto room = connection->room(fragmentParts[1]); + if(!room) { + qWarning() << "Room not found"; + return nullptr; + } + QNetworkRequest r(request); + r.setUrl(QUrl(QStringLiteral("%1/_matrix/media/r0/download/%2").arg(connection->homeserver().toString(), mediaId))); + auto reply = createRequest(QNetworkAccessManager::GetOperation, r); + return new MxcReply(reply, room, fragmentParts[2]); + } else if(fragmentParts.size() == 1) { + auto connection = AccountRegistry::instance().get(fragment); + if(!connection) { + qWarning() << "Connection not found"; + return nullptr; + } + QNetworkRequest r(request); + r.setUrl(QUrl(QStringLiteral("%1/_matrix/media/r0/download/%2").arg(connection->homeserver().toString(), mediaId))); + auto reply = createRequest(QNetworkAccessManager::GetOperation, r); + return new MxcReply(reply); + } else { + qWarning() << "Invalid request"; + return nullptr; + } + } auto reply = QNetworkAccessManager::createRequest(op, request, outgoingData); reply->ignoreSslErrors(d->ignoredSslErrors); return reply; } + +QStringList NetworkAccessManager::supportedSchemesImplementation() const +{ + auto schemes = QNetworkAccessManager::supportedSchemesImplementation(); + schemes += QStringLiteral("mxc"); + return schemes; +} + +QUrl NetworkAccessManager::urlForRoomEvent(Room *room, const QString &eventId, const QString &mediaId) +{ + return QUrl(QStringLiteral("mxc:%1#%2/%3/%4").arg(mediaId, room->connection()->userId(), room->id(), eventId)); +} + +QUrl NetworkAccessManager::urlForFile(Connection *connection, const QString &mediaId) +{ + return QUrl(QStringLiteral("mxc:%1#%2").arg(mediaId, connection->userId())); +} \ No newline at end of file diff --git a/lib/networkaccessmanager.h b/lib/networkaccessmanager.h index 47729a1b..5d262f98 100644 --- a/lib/networkaccessmanager.h +++ b/lib/networkaccessmanager.h @@ -8,6 +8,8 @@ #include namespace Quotient { +class Room; +class Connection; class NetworkAccessManager : public QNetworkAccessManager { Q_OBJECT public: @@ -21,6 +23,10 @@ public: /** Get a pointer to the singleton */ static NetworkAccessManager* instance(); +public Q_SLOTS: + QStringList supportedSchemesImplementation() const; + QUrl urlForRoomEvent(Room *room, const QString &eventId, const QString &mediaId); + QUrl urlForFile(Connection *connection, const QString &mediaId); private: QNetworkReply* createRequest(Operation op, const QNetworkRequest& request, QIODevice* outgoingData = Q_NULLPTR) override; -- cgit v1.2.3