QXmpp Version: 1.11.3
Loading...
Searching...
No Matches
QXmppAccountMigrationManager.h
1// SPDX-FileCopyrightText: 2023 Linus Jahn <lnj@kaidan.im>
2// SPDX-FileCopyrightText: 2024 Filipe Azevedo <pasnox@gmail.com>
3//
4// SPDX-License-Identifier: LGPL-2.1-or-later
5
6#ifndef QXMPPACCOUNTMIGRATIONMANAGER_H
7#define QXMPPACCOUNTMIGRATIONMANAGER_H
8
9#include "QXmppAsync_p.h"
10#include "QXmppClientExtension.h"
11#include "QXmppError.h"
12#include "QXmppTask.h"
13
14#include <any>
15#include <typeindex>
16#include <unordered_map>
17
18struct QXmppExportDataPrivate;
19
20class QXMPP_EXPORT QXmppExportData
21{
22public:
23 template<typename T = QXmpp::Success>
24 using Result = std::variant<T, QXmppError>;
25
26 QXmppExportData();
27 QXMPP_PRIVATE_DECLARE_RULE_OF_SIX(QXmppExportData)
28
29 static std::variant<QXmppExportData, QXmppError> fromDom(const QDomElement &);
30 void toXml(QXmlStreamWriter *) const;
31
32 const QString &accountJid() const;
33 void setAccountJid(const QString &jid);
34
35 template<typename T>
36 std::optional<T> extension() const
37 {
38 const auto it = extensions().find(std::type_index(typeid(T)));
39 return it != extensions().cend() ? std::any_cast<T>(it->second) : std::optional<T>();
40 }
41
42 template<typename T>
43 void setExtension(T &&value)
44 {
45 Q_ASSERT(isExtensionRegistered<T>());
46 setExtension(std::any(std::move(value)));
47 }
48
49 template<typename T>
50 using ExtensionParser = Result<T> (*)(const QDomElement &);
51 template<typename T>
52 using ExtensionSerializer = void (*)(const T &, QXmlStreamWriter &);
53
54 template<typename T, ExtensionParser<T> parse, ExtensionSerializer<T> serialize>
55 static void registerExtension(QStringView tagName, QStringView xmlns)
56 {
57 using namespace QXmpp::Private;
58 using AnyParser = ExtensionParser<std::any>;
59 using AnySerializer = ExtensionSerializer<std::any>;
60
61 AnyParser parseAny = [](const QDomElement &el) {
62 return std::visit(overloaded {
63 [](T data) -> Result<std::any> { return std::move(data); },
64 [](QXmppError e) -> Result<std::any> { return std::move(e); },
65 },
66 parse(el));
67 };
68
69 AnySerializer serializeAny = [](const std::any &data, QXmlStreamWriter &w) {
70 return std::invoke(serialize, std::any_cast<const T &>(data), w);
71 };
72
73 registerExtensionInternal(std::type_index(typeid(T)), parseAny, serializeAny, tagName, xmlns);
74 }
75
76 template<typename T>
77 static bool isExtensionRegistered() { return isExtensionRegistered(std::type_index(typeid(T))); }
78
79private:
81 friend class tst_QXmppAccountMigrationManager;
82
83 const std::unordered_map<std::type_index, std::any> &extensions() const;
84 void setExtension(std::any value);
85
86 static void registerExtensionInternal(std::type_index, ExtensionParser<std::any>, ExtensionSerializer<std::any>, QStringView tagName, QStringView xmlns);
87 static bool isExtensionRegistered(std::type_index);
88
89 QSharedDataPointer<QXmppExportDataPrivate> d;
90};
91
92struct QXmppAccountMigrationManagerPrivate;
93
95{
96 Q_OBJECT
97
98 friend struct QXmppAccountMigrationManagerPrivate;
99
100public:
101 template<typename T = QXmpp::Success>
102 using Result = std::variant<T, QXmppError>;
103
106
107 QXmppTask<Result<>> importData(const QXmppExportData &account);
109
110 template<typename DataType, typename ImportFunc, typename ExportFunc>
111 void registerExportData(ImportFunc importFunc, ExportFunc exportFunc);
112
113 template<typename DataType>
114 void unregisterExportData();
115
116 Q_SIGNAL void errorOccurred(const QXmppError &error);
117
118private:
119 void registerMigrationDataInternal(std::type_index dataType, std::function<QXmppTask<Result<>>(std::any)>, std::function<QXmppTask<Result<std::any>>()>);
120 void unregisterMigrationDataInternal(std::type_index dataType);
121
122 std::unique_ptr<QXmppAccountMigrationManagerPrivate> d;
123};
124
125template<typename DataType, typename ImportFunc, typename ExportFunc>
126void QXmppAccountMigrationManager::registerExportData(ImportFunc importFunc, ExportFunc exportFunc)
127{
128 using namespace QXmpp::Private;
129
130 static_assert(std::is_constructible_v<std::function<QXmppTask<Result<>>(const DataType &)>, ImportFunc>);
131 static_assert(std::is_constructible_v<std::function<QXmppTask<Result<DataType>>()>, ExportFunc>);
132 static_assert(std::is_invocable_v<ImportFunc, const DataType &>);
133 static_assert(std::is_invocable_v<ExportFunc>);
134 static_assert(std::is_same_v<first_argument_t<ImportFunc>, const DataType &>);
135
136 auto importInternal = [importFunc = std::move(importFunc)](std::any data) -> QXmppTask<Result<>> {
137 Q_ASSERT(std::type_index(data.type()) == std::type_index(typeid(DataType)));
138 return importFunc(std::any_cast<DataType>(std::move(data)));
139 };
140
141 using AnyResult = std::variant<std::any, QXmppError>;
142 auto exportInternal = [this, exportFunc = std::move(exportFunc)]() -> QXmppTask<AnyResult> {
143 return chain<AnyResult>(exportFunc(), this, [](Result<DataType> &&result) {
144 return std::visit(overloaded {
145 [](DataType data) -> AnyResult { return std::any(std::move(data)); },
146 [](QXmppError err) -> AnyResult { return err; } },
147 std::move(result));
148 });
149 };
150
151 registerMigrationDataInternal(std::type_index(typeid(DataType)), std::move(importInternal), std::move(exportInternal));
152}
153
154template<typename DataType>
156{
157 unregisterMigrationDataInternal(std::type_index(typeid(DataType)));
158}
159
160#endif
Allows to export and import account data.
Definition QXmppAccountMigrationManager.h:95
std::variant< T, QXmppError > Result
Definition QXmppAccountMigrationManager.h:102
void unregisterExportData()
Definition QXmppAccountMigrationManager.h:155
void registerExportData(ImportFunc importFunc, ExportFunc exportFunc)
Definition QXmppAccountMigrationManager.h:126
Q_SIGNAL void errorOccurred(const QXmppError &error)
The QXmppClientExtension class is the base class for QXmppClient extensions.
Definition QXmppClientExtension.h:32
Definition QXmppTask.h:46
Definition QXmppError.h:17