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